0

Entity Framework와 조건부 연결을 만들고 싶습니다. 아는 한 조건부 외래 키를 만들 수 없으므로 데이터베이스 서버 수준에서이 문제를 해결할 수 없습니다. 내가 그와 같은 테이블이 있습니다Entity Framework와 조건부 연결

---Property--- 
int  id 
string Name 
int  TypeId  --> Condition on this. 
int  ValueId 

---ValueString--- 
int  id 
string Value 

---ValueInteger--- 
int  id 
int  Value 

---ValueBoolean--- 
int  id 
bool Value 

지금, 속성 테이블의 유형 ID 필드는 값의 종류가 포함되어 있습니다. 예를 들어, 유형 ID == 1, 다음 ValueInteger 테이블에 ValueId 점 등

내가 몇 가지 해결 방법을 한 경우 유형 ID == 0 경우, 다음, 여기서, valueString 테이블에 포인트를 ValueId하지만 어딘가에 붙어 :

나는 그런 열거 있습니다

public enum PropertyType 
{ 
    String = 0, 
    Integer = 1, 
    Boolean = 2, 
    DateTime = 3, 
    List = 4 
} 

을 나는 그런 부분 클래스 구현 :

public partial class ProductProperty : EntityObject 
{ 
    public object Value 
    { 
     get 
     { 
      switch (Property.Type) 
      { 
       case PropertyType.String: 
        return ValueString.Where(w => w.id == this.ValueId).Select(s => s);//how to return? 
        break; 
       case PropertyType.Integer: 
        return ValueInteger.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       case PropertyType.Boolean: 
        return ValueBoolean.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       case PropertyType.DateTime: 
        return ValueDateTime.Where(w => w.id == this.ValueId).Select(s => s) //how to return? 
        break; 
       default: 
        return null; 
        break; 
      } 
     } 
     set 
     { 

     } 
    } 
} 

을하지만 나는 EntityObject에서 컨텍스트 개체에 도달하는 방법을 모른다 , 그래서 Property EntityObject의 Value * 테이블에 접근 할 수 없었습니다.

그래서이 접근법은 사실입니까, 아니면 어떻게해야합니까? 그것이 사실이라면 EntityObject에서 엔티티 컨텍스트 개체를 어떻게 얻을 수 있습니까?

수정 :이 방법을 제안하지 않으면 무엇을 제안합니까? 의견을 보내주십시오. 나는이 방법의 가장 좋은 대안이 같은 수 있습니다 생각 : 나는 다른 값 유형을 추가하려면

---Property--- 
int  id 
string ValueString 
int  ValueInteger 
bool ValueBoolean 
etc... 

그러나이 방법은, 내가 테이블 구조를 변경해야합니다, 나는 개체를 업데이트해야합니다 내 프로젝트의 개체 모델. 값에 대한 데이터를 필터링해야하므로 직렬화 된 객체를 사용할 수 없습니다. 편집이 종료

+0

일부 DB (Oracle)는 이러한 키를 허용합니다. 당신은 당신이 사용하는 DB를 언급하지 않습니다. 그렇지만이 디자인은 표준 SQL DB 또는 EF에 적합하지 않습니다. 다른 방법으로 문제를 해결할 것을 권합니다. –

+0

감사합니다. Craig, MS SQL Server를 사용하고 있습니다. 코드에서 추가 공용 함수를 사용하여이 문제를 관리 할 수 ​​있습니다. 그러나 그것은 단지 내 팀원들을 혼란스럽게하고 더 복잡한 일을합니다. 나는 (문자열) SomeProperty.Value 또는 (int) SomeProperty.Value와 같은 것을 사용하는 접근법이 필요하다. 나는 속성의 값을 얻기 위해 여분의 함수를 구현하고 싶지 않다. – oruchreis

답변

3

나는 당신이 관계형 측과 객체 지향 쪽은 데이터베이스의 TPC 추상화, 매핑 및 개체 모델입니다 모두에 맞는을 얻을 수있을 것 같아요 가장 가까운 이미 테이블 구조에 매우 가깝습니다. 간단히하기 위해 EF 4.3.1에서 코드 우선을 사용하여 이것을 보여 드리겠습니다. (그냥 쉽게 우리가 이러한 클래스를 사용하는 경우에 무슨 일이 일어나고 있는지 볼 수 있도록 나는 약간의 toString 방법에 넣어.)

public class Property 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int ValueId { get; set; } 
    public virtual Value Value { get; set; } 
} 

public abstract class Value 
{ 
    public int Id { get; set; } 
} 

public class ValueString : Value 
{ 
    public string Value { get; set; } 

    public override string ToString() 
    { 
     return "String value of " + Value; 
    } 
} 

public class ValueInteger : Value 
{ 
    public int Value { get; set; } 

    public override string ToString() 
    { 
     return "Integer value of " + Value; 
    } 
} 

public class ValueBoolean : Value 
{ 
    public bool Value { get; set; } 

    public override string ToString() 
    { 
     return "Boolean value of " + Value; 
    } 
} 

이 수 :

의 지금 같은 간단한 개체 모델을 정의 할 수 유형 ID 공동 것을 제외하고

public class PropertyAndValuesContext : DbContext 
{ 
    public DbSet<Property> Properties { get; set; } 
    public DbSet<Value> Values { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<ValueString>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueString"); 
      }); 

     modelBuilder.Entity<ValueInteger>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueInteger"); 
      }); 

     modelBuilder.Entity<ValueBoolean>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ValueBoolean"); 
      }); 
    } 
} 

는 이제 테이블이 우리가, 당신은 당신의 질문의 시작에 제공되는 레이아웃과 일치해야 : 각 유형은 자신의 표를 얻을 수 있도록 TPC를 사용하여 매핑 할 수 여기서 nural 열은 필요하지 않으므로 누락되었습니다.

public class TestInitializer : DropCreateDatabaseAlways<PropertyAndValuesContext> 
{ 
    protected override void Seed(PropertyAndValuesContext context) 
    { 
     new List<Property> 
     { 
      new Property { Name = "PropWithBool", Value = new ValueBoolean { Id = 1, Value = true } }, 
      new Property { Name = "PropWithString1", Value = new ValueString { Id = 2, Value = "Magic" } }, 
      new Property { Name = "PropWithString2", Value = new ValueString { Id = 3, Value = "Unicorn" } }, 
      new Property { Name = "PropWithInt1", Value = new ValueInteger { Id = 4, Value = 6 } }, 
      new Property { Name = "PropWithInt2", Value = new ValueInteger { Id = 5, Value = 7 } }, 
     }.ForEach(p => context.Properties.Add(p)); 
    } 
} 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     Database.SetInitializer(new TestInitializer()); 

     using (var context = new PropertyAndValuesContext()) 
     { 
      foreach (var property in context.Properties) 
      { 
       Console.WriteLine("{0} with {1}", property.Name, property.Value); 
      } 
     } 
    } 
} 

가 실행이 출력합니다 :

의가 초기화 및 콘솔 응용 프로그램은 테스트 데이터를 추가하고 표시 할 쓰자

PropWithBool with Boolean value of True 
PropWithString1 with String value of Magic 
PropWithString2 with String value of Unicorn 
PropWithInt1 with Integer value of 6 
PropWithInt2 with Integer value of 7 

당신은 우리가 쉽게 수 있는지 볼 수 있습니다 다른 유형의 값을 추가하고 해당 테이블에 저장 한 다음이 값을 다시 조회하십시오.

어쩌면 당신은 정말로 당신의 예제 에서처럼 "object"로 입력 된 값을 반환하는 속성을 원할 것입니다. 음, 우리는 이제 단순한 추상적 인 속성을 사용하여이 작업을 수행 할 수 있습니다

public abstract class Value 
{ 
    public int Id { get; set; } 

    public abstract object TheValue { get; set; } 
} 

public class ValueString : Value 
{ 
    public string Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (string)value; } 
    } 

    public override string ToString() 
    { 
     return "String value of " + Value; 
    } 
} 

public class ValueInteger : Value 
{ 
    public int Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (int)value; } 
    } 

    public override string ToString() 
    { 
     return "Integer value of " + Value; 
    } 
} 

public class ValueBoolean : Value 
{ 
    public bool Value { get; set; } 

    public override object TheValue 
    { 
     get { return Value; } 
     set { Value = (bool)value; } 
    } 

    public override string ToString() 
    { 
     return "Boolean value of " + Value; 
    } 
} 

당신이 원하는 경우에 당신은이 일을 상상할 수 :

public class Property 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int ValueId { get; set; } 
    public virtual Value Value { get; set; } 

    public object TheValue 
    { 
     get { return Value.TheValue; } 
     set { Value.TheValue = value; } 
    } 
} 

마지막으로, 당신이 정말로 유형 ID 속성을 필요로하는 경우/열을에 Property entity/table을 추가 할 수는 있지만 매핑에 필요하지 않으므로 적절한 값으로 설정해야합니다.

+0

와우, 훌륭한 대답. 나는 지금 그것을 읽고 있는데, 나는 내 프로젝트에 지원함으로써 이해하려고 노력하고있다. 성공 후 나는 이것을 대답으로 받아 들일 것이다. 고마워. – oruchreis

0

아서의 대답은 대답이지만 내 결과를 공유하고 싶습니다.

먼저 속성 값을 제네릭 형식으로 구현하려고했습니다. 그리고 나서 모든 ValueString, ValueInteger 등을 구현했습니다. 이 제네릭 형식에서 작동하는 클래스 그것은 작동했지만 일반적인 유형의 접근법은 사용법에 많은 주조를 일으켰습니다. 그래서 객체 값을 고수했습니다.

public class ProductProperty 
{ 
    public int ProductPropertyId { get; set; } 
    public Product Product { get; set; } 
    public int TypeId { get; set; } 
    public int ValueId { get; set; } 
    [ForeignKey("TypeId")] 
    public PropertyType Type { get; set; } 
    [ForeignKey("ValueId")] 
    public PropertyValue Value { get; set; } 
} 

이 호텔의 유형 :

이것은 가치와 유형을 보유 속성 클래스입니다. 예를 들어,이 속성 유형은 간단한 유형이 문자열 일 수있는 "Name"일 수도 있고 간단한 유형이 될 "Price"일 수도 있습니다 흙손.

public class PropertyType 
{ 
    public int PropertyTypeId { get; set; } 
    [MaxLength(150)] 
    public string Name { get; set; } 

    //For before EF 5, there is no enum support 
    [Column("SimpleType")] 
    public int InternalSimpleType { get; set; } 
    [NotMapped] 
    public SimpleType SimpleType 
    { 
     get { return (SimpleType)InternalSimpleType; } 
     set { InternalSimpleType = (int)value; } 
    } 

    public ICollection<ProductProperty> ProductProperties { get; set; } 
} 

public enum SimpleType : int 
{ 
    String = 1, 
    Integer = 2, 
    Float = 4, 
    Boolean = 8, 
    DateTime = 16, 
    List = 32 
} 

이 아서 생각 gived이 값 테이블에 대한 추상 기본 클래스입니다 :

public class PropertyValueString : PropertyValue 
{ 
    [Column("Value", TypeName="ntext")] 
    public string InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (string)InternalValue; 
     } 
     set 
     { 
      InternalValue = (string)value; 
     } 
    } 
} 

public class PropertyValueInteger : PropertyValue 
{ 
    [Column("Value")] 
    public int InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (int)InternalValue; 
     } 
     set 
     { 
      InternalValue = (int)value; 
     } 
    } 
} 

public class PropertyValueBoolean : PropertyValue 
{ 
    [Column("Value")] 
    public bool InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (bool)InternalValue; 
     } 
     set 
     { 
      InternalValue = (bool)value; 
     } 
    } 
} 

public class PropertyValueFloat : PropertyValue 
{ 
    [Column("Value")] 
    public float InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (float)InternalValue; 
     } 
     set 
     { 
      InternalValue = (float)value; 
     } 
    } 
} 

public class PropertyValueDateTime : PropertyValue 
{ 
    [Column("Value", TypeName = "datetime2")] 
    public DateTime InternalValue { get; set; } 
    public override object Value 
    { 
     get 
     { 
      return (DateTime)InternalValue; 
     } 
     set 
     { 
      InternalValue = (DateTime)value; 
     } 
    } 
} 

이것은 conext에있을 것입니다 :

public abstract class PropertyValue 
{ 
    [Key] 
    public int PropertyValueId { get; set; } 
    [NotMapped] 
    public abstract object Value { get; set; } 
} 

을이 값 클래스/테이블입니다 DbContext로부터의 클래스 :

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<PropertyValueString>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueString"); 
      }); 

     modelBuilder.Entity<PropertyValueInteger>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueInteger"); 
      }); 

     modelBuilder.Entity<PropertyValueBoolean>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueBoolean"); 
      }); 

     modelBuilder.Entity<PropertyValueFloat>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueFloat"); 
      }); 

     modelBuilder.Entity<PropertyValueDateTime>().Map(
      m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("PropertyValueDateTime"); 
      }); 

그래서 내 문제가 해결되었습니다. 그리고 저는 이것을 나누고 싶었습니다.

관련 문제