Как сначала разделить таблицу на несколько типов в коде EF4?

Я использую POCO с первым кодом с EF4, CTP5. У меня есть таблица с большим количеством столбцов (более 100). Я хочу разделить таблицу на несколько типов (так называемое «Разделение таблицы»), чтобы мне не приходилось каждый раз извлекать все данные, когда мне нужна основная информация.

Кажется, я не могу найти никакой документации по этому поводу с помощью Google. Я нашел ссылки на концепцию «Разбиение таблицы», а также видел, как это сделать с помощью файла EDMX, но не нашел примеров для кода.

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

public class User
{
    public int UserID { get; set; }
    public string UserName { get; set; }
    [ForeignKey("UserID")]
    public virtual UserDetails Details { get; set; }
}

public class UserDetails
{
    public int UserID { get; set; }
    public string MoreData { get; set; }
    [ForeignKey("UserID")]
    public virtual User User { get; set; } // nice to have, but not required
}

И я называю это так...

return (from u in Context.Users  // <-- error occurs here
        where u.UserID == userID
        select u).FirstOrDefault();

К сожалению, похоже, это не работает. Я получаю следующую ошибку, когда я делаю это...

[IndexOutOfRangeException: Index was outside the bounds of the array.]
   System.Data.Entity.ModelConfiguration.Conventions.Edm.PropertyMaxLengthConvention.System.Data.Entity.ModelConfiguration.Conventions.Edm.IEdmConvention<System.Data.Edm.EdmAssociationType>.Apply(EdmAssociationType associationType, EdmModel model) +598
   System.Data.Entity.ModelConfiguration.Configuration.EdmConventionDispatcher.Dispatch(TEdmDataModelItem item) +100
   System.Data.Entity.ModelConfiguration.Configuration.EdmConventionDispatcher.VisitEdmAssociationType(EdmAssociationType item) +22
   System.Data.Entity.ModelConfiguration.Edm.Services.DataModelItemVisitor.VisitCollection(IEnumerable`1 collection, Action`1 visitMethod) +267
   System.Data.Entity.ModelConfiguration.Edm.Services.EdmModelVisitor.VisitAssociationTypes(EdmNamespace edmNamespace, IEnumerable`1 associationTypes) +75
   System.Data.Entity.ModelConfiguration.Edm.Services.EdmModelVisitor.VisitEdmNamespace(EdmNamespace item) +91
   System.Data.Entity.ModelConfiguration.Configuration.EdmConventionDispatcher.VisitEdmNamespace(EdmNamespace item) +32
   System.Data.Entity.ModelConfiguration.Edm.Services.DataModelItemVisitor.VisitCollection(IEnumerable`1 collection, Action`1 visitMethod) +267
   System.Data.Entity.ModelConfiguration.Edm.Services.EdmModelVisitor.VisitNamespaces(EdmModel model, IEnumerable`1 namespaces) +75
   System.Data.Entity.ModelConfiguration.Edm.Services.EdmModelVisitor.VisitEdmModel(EdmModel item) +47
   System.Data.Entity.ModelConfiguration.Configuration.EdmConventionDispatcher.VisitEdmModel(EdmModel item) +45
   System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.ApplyModel(EdmModel model) +254
   System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo, Boolean validateModel) +257
   System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbConnection providerConnection) +172
   System.Data.Entity.Internal.LazyInternalContext.CreateModel() +62
   System.Lazy`1.CreateValue() +361
   System.Lazy`1.LazyInitValue() +104
   System.Lazy`1.get_Value() +89
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +358
   System.Data.Entity.Internal.InternalContext.Initialize() +16
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +16
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +61
   System.Data.Entity.Internal.Linq.InternalSet`1.get_Provider() +15
   System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() +13
   System.Linq.Queryable.Where(IQueryable`1 source, Expression`1 predicate) +63
   TourFactory.Web.AgentWebsite.Models.Websites.WebsiteRepository.GetUser(Int32 userID) in C:\Code\hdtf\TF4\Web\AgentWebsite\Models\Websites\WebsiteRepository.cs:28
   TourFactory.Web.AgentWebsite.Controllers.WebsiteController.get_Agent() in C:\Code\hdtf\TF4\Web\AgentWebsite\Controllers\WebsiteController.cs:42
   TourFactory.Web.AgentWebsite.Controllers.WebsiteController.OnActionExecuting(ActionExecutingContext filterContext) in C:\Code\hdtf\TF4\Web\AgentWebsite\Controllers\WebsiteController.cs:55
   System.Web.Mvc.Controller.System.Web.Mvc.IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) +39
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +81
   System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +61
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +305
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +830
   System.Web.Mvc.Controller.ExecuteCore() +136
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +232
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +39
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +68
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +44
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +42
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +141
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +54
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +61
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +31
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +56
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +110
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8841105
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

Удаление свойства User.Details устраняет ошибку, но тогда я не могу использовать изящные функции навигации EF4.


person Brian    schedule 19.01.2011    source источник


Ответы (3)


Использование сложных типов — единственный способ сопоставить таблицу с несколькими типами. Однако Code First (и EF в целом) НЕ поддерживает ленивую/отложенную загрузку для сложных типов. Другими словами, EF всегда будет заполнять сложный тип каждый раз, когда вы читаете сущность из базы данных:

public class User
{
    public int UserID { get; set; }
    public string UserName { get; set; }
    public UserDetails Details { get; set; }
}

[ComplexType]
public class UserDetails
{
    public string MoreData { get; set; }
}

Единственный способ добиться ленивой загрузки для вашей большой таблицы — это действительно разделить ее на несколько таблиц, а затем вы можете использовать ассоциации «один к одному», чтобы сопоставить ее с несколькими сущностями.

Дополнительные сведения о сложных типах в EF Code First CTP см. в этой статье:
Ассоциации в EF Code First CTP5: часть 1 — сложные типы< /а>

person Morteza Manavi    schedule 19.01.2011
comment
Спасибо. Я надеялся на лучшее решение. Я начинаю задаваться вопросом, нужно ли мне переключаться на NHibernate для поддержки нашей устаревшей базы данных. - person Brian; 20.01.2011
comment
Извини, чувак, я бы хотел, чтобы у меня был лучший ответ для тебя. Я думаю, что NHibernate поддерживает эту функцию для сложных типов (они называют это Components, но это та же концепция). К сожалению, это низкоприоритетный элемент для команды EF, поэтому очень маловероятно, что мы получим эту функцию в RTM позже в этом году. - person Morteza Manavi; 20.01.2011
comment
@Brian: Просто используйте проекцию в своих запросах, и все будет в порядке. Или откажитесь от Code First и используйте функцию QueryView. - person Ladislav Mrnka; 20.01.2011

Я знаю, что этому вопросу больше года, но EF Code First поддерживает одновременное разделение таблиц и отложенную загрузку.

Ваша модель должна быть такой:

[Table("UserTable")]
public class User
{
    [Key, ForeignKey("Details")]
    public int UserID { get; set; }
    public string UserName { get; set; }
    public virtual  UserDetails Details { get; set; }
}

[Table("UserTable")]
public class UserDetails
{

    [Key, ForeignKey("User")]
    public int UserID { get; set; }
    public string MoreData { get; set; }
    public virtual User User { get; set; }
}

Ленивая загрузка (и активная загрузка) должны работать должным образом.

Важно отметить, что разбиение таблицы работает, если

  • Сущности имеют отношение 1 к 1, и
  • Сущности имеют один и тот же ключ
person rino.batin    schedule 27.05.2012

Я думаю, что ответ, предложенный Рино, лучше. Хотя в итоге вы добиваетесь того же. Но в случае со вторым он должен делать то же самое. Во-первых, может возникнуть проблема, когда вы не можете применить [ComplexType] из-за стороннего кода или у вас есть список этого типа.

Используйте второй или как в API-интерфейсах Fluent, как в книге Джулии Лерман (разделение таблицы «Люди» на сущности «Персона» и «ПерсонФото».

   modelBuilder.Entity<Person>().ToTable("People");
   modelBuilder.Entity<PersonPhoto>().ToTable("People");
person user2224280    schedule 02.04.2013