Как реализовать стратегию типа «таблица на конкретный тип» с использованием структуры сущностей - PullRequest
5 голосов
/ 15 марта 2010

Я сопоставляю набор таблиц с общим набором полей:

alt text

Итак, как вы можете видеть, я использую стратегию типа таблица-на-бетон для отображения наследования.

Но ...

Я не мог бы связать их с абстрактным типом, содержащим эти общие свойства.

Можно сделать это с помощью EF?


БОНУС: Единственное недокументированное Entity Data Model Mapping Scenario это Table-per-concrete-type inheritance http://msdn.microsoft.com/en-us/library/cc716779.aspx: P

Ответы [ 5 ]

5 голосов
/ 17 марта 2010

Наконец Я создал интерфейс 'Iggy' , который содержал средства доступа к общим свойствам:

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

и использовали частичные классы для реализации его в классах домена

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

C # действительно очень удобен, и хотя я хотел бы сделать это, используя функцию Entity Framework, частичные функции работают как шарм:)

1 голос
/ 15 марта 2010

Почему бы не исправить дизайн стола?!

0 голосов
/ 06 октября 2015

Мне нравится ответ @SDReyes выше. Но использование интерфейса и частичных классов не всегда удобно. При использовании интерфейса вы должны обязательно повторить один и тот же набор аксессоров интерфейса по умолчанию в каждом унаследованном частичном классе. В случае одного наследования использование абстрактного класса намного удобнее. По умолчанию абстрактный класс даст точно желаемое отображение:

Таблица для конкретного класса (TPC): этот подход предлагает одну таблицу для один конкретный класс, но не для абстрактного класса. Итак, если вы наследуете абстрактный класс в нескольких конкретных классах, затем свойства абстрактного класса будет частью каждой таблицы конкретного класс.

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

Затем мы можем переписать код с помощью @SDReyes следующим образом:

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

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

Мы можем оставить определения Ала, Бена и Карла пустыми. Все унаследованные поля от Игги будут автоматически взяты из определения Игги в отдельную таблицу для каждого класса.

0 голосов
/ 18 июня 2013

На самом деле, использование частичных классов для реализации интерфейса действительно решит вашу проблему, если у вас есть только несколько таблиц (сущностей), которые вы хотите отобразить. Но когда вам нужно сделать это с большим количеством сущностей или с еще большим количеством интерфейсов, вы может использовать шаблон T4, используемый EF для генерации классов, а затем реализовать интерфейс непосредственно в автоматически сгенерированных классах POCO без необходимости ручной работы.

Я сделал это сам, мы создали интерфейс ISimpleAuditable, очень похожий на ваш, и T4 проверяет, есть ли в таблице правильные поля, и, если это так, добавит код реализации интерфейса в класс.

Мы создали файл Include.tt, который имеет следующий код:

открытая статическая строка GetTypeInterfaces (EntityType entity) { string interfaces = 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;
}

Код T4 выглядит примерно так:

<#@ 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)#>
<#
    }
}
#>

Обратите внимание, что это не полный T4, но вы можете понять это

0 голосов
/ 11 октября 2010

Я достиг этого точного сценария сегодня. Кажется, дизайнер не делает это правильно, но вот как я это сделал, изменив EDMX: -

  1. В базовый класс поместите все ваши общие свойства, например, дату изменения и изменения. Вы можете сделать это в разделе CSDL. Не ставьте никаких условий на CSDL.
  2. В содержимом сопоставления C-S вставьте сопоставления ваших полей. Очевидно, вам необходимо сопоставить на обоих дочерних объектах общие свойства со столбцами физической БД.
  3. Поместите условие в каждую таблицу, где столбец PK, например. Идентификатор устанавливает IsNull = false.

Если вы затем снова откроете конструктор, вы увидите, что общие поля находятся в базовом классе, и единственными полями, которые появляются в производных типах (в области Сопоставления столбцов), будут уникальные столбцы.

По крайней мере, у меня это сработало: -)

...