2010-03-15 20 views
5

Tôi đang lập bản đồ một tập hợp các bảng có chung một bộ chung của lĩnh vực:Làm thế nào để thực hiện bảng mỗi bê tông kiểu chiến lược sử dụng Entity Framework

alt text

Như bạn có thể thấy tôi sử dụng chiến lược loại bảng cho mỗi bê tông để lập bản đồ thừa kế.

Nhưng ...

tôi đã không thể liên hệ chúng với một loại trừu tượng chứa những tài sản chung.

Bạn có thể làm điều đó bằng EF?


BONUS: Các chỉ phi tài liệu Entity Data Model Mapping ScenarioTable-per-concrete-type inheritancehttp://msdn.microsoft.com/en-us/library/cc716779.aspx: P

+0

http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete -type-tpc-and-select-strategy-guidelines.aspx –

Trả lời

5

Cuối cùng Tôi tạo ra một giao diện 'Iggy' có chứa accessors đến tài sản chung:

public Interface Iggy 
{ 
    string modifiedBy { get; set; } 
    DateTime modifiedDate { get; set; } 
} 

sử dụng các lớp học phần để thực hiện nó trong các lớp miền

public partial class Al:Iggy{} 
public partial class Ben:Iggy{} 
public partial class Carl:Iggy{} 

C# thực sự rất tiện dụng và mặc dù tôi muốn làm điều đó bằng cách sử dụng tính năng khung thực thể, partials làm việc như một nét duyên dáng:)

1

Tại sao không sửa chữa các thiết kế bảng ?!

+0

Xin chào Reinier! cảm ơn cho đề xuất của bạn:). nhưng thực sự nó sẽ dẫn đến rất tốn kém (có ~ 150 bảng trong dự án) vì vậy tôi sẽ xem xét nó trong lần lặp tiếp theo. ngay bây giờ, chúng tôi muốn thực hiện nó theo cách này, tránh một nhà tái cấu trúc khổng lồ. cũng có rất nhiều sự cân bằng giữa các chiến lược, điều này là tốt ở hiệu suất (tránh rất nhiều sự gia nhập chống lại một bảng trung tâm). cảm ơn lần nữa :). – SDReyes

+0

BTW Tôi giả sử bạn đang nói về một chiến lược thừa kế Bảng cho mỗi loại. (offtopic):) – SDReyes

+1

Chắc chắn, bạn lưu vào các kết nối. Nhưng tôi không biết làm thế nào để giúp bạn, xin lỗi. – reinierpost

0

Tôi đã đạt được kịch bản chính xác này ngay hôm nay. Nhà thiết kế dường như không làm điều đó đúng cách, nhưng dưới đây là cách tôi đã làm điều đó bằng cách sửa đổi EDMX: -

  1. Trong lớp cơ sở, hãy đặt tất cả các thuộc tính được chia sẻ của bạn, ví dụ: ngày sửa đổi và sửa đổi. Bạn có thể làm điều này trong phần CSDL. Không đặt bất kỳ điều kiện nào lên CSDL.
  2. Trong nội dung ánh xạ C-S, hãy đặt ánh xạ của các trường của bạn. Rõ ràng bạn cần ánh xạ trên cả hai thực thể con các thuộc tính được chia sẻ với các cột DB vật lý.
  3. Đặt điều kiện trên mỗi bảng trong đó cột PK, ví dụ: Id bộ IsNull = false.

Nếu sau đó bạn mở lại nhà thiết kế, bạn sẽ thấy trường được chia sẻ nằm trong lớp cơ sở và trường duy nhất xuất hiện trên các loại có nguồn gốc (trong khu vực Cột ánh xạ) sẽ là các cột duy nhất.

Ít nhất, điều này làm việc cho tôi :-)

0

Trên thực tế, sử dụng các lớp học phần để thực hiện giao diện thực sự giải quyết vấn đề của bạn nếu bạn có chỉ là một vài bảng (thực thể) mà bạn muốn map.But khi bạn cần thực hiện điều này với nhiều thực thể hơn hoặc thậm chí nhiều giao diện hơn, bạn có thể sử dụng mẫu T4 được EF sử dụng để tạo các lớp và sau đó thực hiện giao diện trực tiếp tại các lớp được tạo tự động POCO, không cần công việc thủ công.

Tôi đã tự làm điều này, chúng tôi đã tạo giao diện ISimpleAuditable, rất giống với giao diện của bạn và T4 kiểm tra xem bảng có đúng trường hay không và nếu có, nó sẽ thêm mã triển khai giao diện vào lớp.

Chúng tôi đã tạo ra một tập tin Include.tt có mã như thế này:

public static string GetTypeInterfaces (EntityType tổ chức) { chuỗi giao diện = String.Empty;

if(IsNome(entity)) 
    { 
     if(IsIdentifiableNumeric(entity)) 
      interfaces = "IEntity<int>"; 

     if(IsIdentifiableText(entity)) 
      interfaces = "IEntity<string>"; 

     if (interfaces == String.Empty) 
      interfaces = "INome"; 

     if(IsSimpleAuditable(entity)) 
      if (interfaces==String.Empty) 
       interfaces = "ISimpleAuditable<string>"; 
      else 
       interfaces += ", ISimpleAuditable<string>"; 
    } 
    else 
    { 
     if(IsIdentifiableNumeric(entity)) 
      interfaces = "IIdentifiable<int>"; 

     if(IsIdentifiableText(entity)) 
      interfaces = "IIdentifiable<string>"; 

     if(IsSimpleAuditable(entity)) 
      if (interfaces==String.Empty) 
       interfaces = "ISimpleAuditable<string>"; 
      else 
       interfaces += ", ISimpleAuditable<string>"; 
    } 
    if (interfaces != string.Empty) 
     if (entity.BaseType !=null) 
      interfaces = string.Format(", {0}", interfaces); 
     else 
      interfaces = string.Format(": {0}", interfaces); 

    return interfaces; 
} 

Mã T4 trông giống như sau:

<#@ template language="C#" debug="true" hostspecific="true"#> 
<#@ import namespace="System.Diagnostics" #> 
<#@ include file="EF.Utility.CS.ttinclude"#> 
<#@ include file="Winsys.Sandstone.Data.ttinclude"#><#@ 
output extension=".cs"#><# 

const string inputFile = @"Winsys.Sandstone.Data.edmx"; 
var textTransform = DynamicTextTransformation.Create(this); 
var code = new CodeGenerationTools(this); 
    var ef = new MetadataTools(this); 
var typeMapper = new TypeMapper(code, ef, textTransform.Errors); 
var fileManager = EntityFrameworkTemplateFileManager.Create(this); 
var itemCollection = new EdmMetadataLoader(textTransform.Host, TextTransform.Errors).CreateEdmItemCollection(inputFile); 
var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); 

if  (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) 
{ 
return string.Empty; 
} 

WriteHeader(codeStringGenerator, fileManager); 

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) 
{ 
fileManager.StartNewFile(entity.Name + ".cs"); 
BeginNamespace(code); 
#> 
<#=codeStringGenerator.UsingDirectives(inHeader: false)#> 
<#=codeStringGenerator.EntityClassOpening(entity)#> 
{ 
<# 
    var propertiesWithDefaultValues =  typeMapper.GetPropertiesWithDefaultValues(entity); 
    var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity); 
    var complexProperties = typeMapper.GetComplexProperties(entity); 

    if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) 
    { 
#> 
    public <#=code.Escape(entity)#>() 
    { 
<# 
     foreach (var edmProperty in propertiesWithDefaultValues) 
     { 
#> 
     this.<#=code.Escape(edmProperty)#> =   <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; 
<# 
     } 

     foreach (var navigationProperty in collectionNavigationProperties) 
     { 
#> 
     this.<#=code.Escape(navigationProperty)#> = new  List<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); 
<# 
     } 

     foreach (var complexProperty in complexProperties) 
     { 
#> 
     this.<#=code.Escape(complexProperty)#> = new   <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); 
<# 
     } 
#> 
    } 

<# 
    } 

var simpleProperties = typeMapper.GetSimpleProperties(entity); 
if (simpleProperties.Any()) 
{ 
    foreach (var edmProperty in simpleProperties) 
    { 
#> 
<#=codeStringGenerator.Property(edmProperty)#> 
<# 
    } 
} 

if (complexProperties.Any()) 
{ 
#> 

<# 
    foreach(var complexProperty in complexProperties) 
    { 
#> 
<#=codeStringGenerator.Property(complexProperty)#> 
<# 
    } 
} 

var navigationProperties = typeMapper.GetNavigationProperties(entity); 
if (navigationProperties.Any()) 
{ 
#> 
<#=WinsysGenerator.GetSimpleAuditable(entity)#> 
<# 
    foreach (var navigationProperty in navigationProperties) 
    { 
#> 
<#=codeStringGenerator.NavigationProperty(navigationProperty)#> 
<# 
    } 
} 
#> 

Lưu ý rằng đây không phải là toàn bộ T4, nhưng bạn có thể lấy ý tưởng

0

Tôi thích câu trả lời bằng @SDReyes trên. Nhưng việc sử dụng giao diện và các lớp học một phần không phải lúc nào cũng thuận tiện. Khi bạn sử dụng giao diện, bạn nên bắt buộc lặp lại cùng một bộ truy cập giao diện mặc định trong mỗi lớp từng phần được thừa hưởng. Trong trường hợp thừa kế đơn, sử dụng lớp trừu tượng sẽ thuận tiện hơn nhiều. Theo mặc định, lớp trừu tượng sẽ cung cấp cho chính xác bản đồ mong muốn:

Bảng cho mỗi lớp bê tông (TPC): Phương pháp này đề xuất một bảng cho một lớp bê tông chứ không phải cho lớp trừu tượng. Vì vậy, nếu bạn thừa hưởng lớp trừu tượng trong nhiều lớp cụ thể, thì các thuộc tính của lớp trừu tượng sẽ là một phần của mỗi bảng của lớp bê tông .

http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx

Sau đó, chúng ta có thể viết lại mã bởi @SDReyes như sau:

public abstract class Iggy 
{ 
    string modifiedBy { get; set; } 
    DateTime modifiedDate { get; set; } 
} 

public class Al:Iggy{} 
public class Ben:Iggy{} 
public class Carl:Iggy{} 

Chúng ta có thể rời khỏi Al, Ben và Carl các định nghĩa sản phẩm nào. Tất cả các trường kế thừa từ Iggy sẽ được tự động lấy từ định nghĩa của Iggy vào một bảng riêng lẻ cho mỗi lớp.

Các vấn đề liên quan