EF6无法构建表拆分/共享主键+基类模型?
题
问题
我正在尝试使用表拆分分享大型表(200 +字段)左右〜7个实体,按照我的上一个问题。
ef6需要导航属性不仅仅是从主模型到子模型,而且在所有子模型(吸吮)之间。
手动解决方案
这可以手动完成:
public class Franchise
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; }
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
[Table("Franchise")]
public class FranchiseEntity
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; } // Ignored, but relevant when inheritance involved, below...
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
[Table("Franchise")]
public class FranchiseMiscellaneous
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set;
public virtual FranchiseMiscellaneous Miscellaneous { get; set; } // Ignored, but relevant when inheritance involved, below...
}
.
流畅映射:
public class FranchiseMapping : EntityTypeConfiguration<Franchise>
{
public FranchiseMapping()
{
HasRequired(x => x.Entity).WithRequiredPrincipal();
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal();
}
}
public class FranchiseEntityMapping : EntityTypeConfiguration<FranchiseEntity>
{
public FranchiseEntityMapping()
{
Ignore(x => x.Entity);
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal(x => x.Entity);
}
}
public class FranchiseMiscellaneousMapping : EntityTypeConfiguration<FranchiseMiscellaneous>
{
public FranchiseMiscellaneousMapping()
{
Ignore(x => x.Miscellaneous);
}
}
.
这是作品。但它不会用7+型号扩展。
尝试改进#1
我想通过遗传+干燥原理提高:
public abstract class SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; }
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
public class Franchise : SharedFranchiseIdBase { ... }
public class FranchiseEntity : SharedFranchiseIdBase { ... }
public class FranchiseMiscellaneous : SharedFranchiseIdBase { ... }
// Maybe generalize the mapping code too...
.
但是,这在第一个请求中失败了“序列包含多个匹配元素”:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Sequence contains more than one matching element
Result StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.ConfigureDependentBehavior(AssociationType associationType, EdmModel model, EntityTypeConfiguration entityTypeConfiguration)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(NavigationProperty navigationProperty, EdmModel model, EntityTypeConfiguration entityTypeConfiguration)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociations(EntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel model)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
... // my test query function
.
尝试改进#2
我以为我可以宣布他们摘要,所以至少程序员被迫实现正确的成员(仍然很难在每个派生类上重新声明):
public abstract class SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public abstract FranchiseEntity Entity { get; set; }
public abstract FranchiseMiscellaneous Miscellaneous { get; set; }
}
public class Franchise : SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public override FranchiseEntity Entity { get; set; }
public override FranchiseMiscellaneous Miscellaneous { get; set; }
}
//etc for other classes
.
但是在相同的错误时失败。呵呵??除了它们被声明为“覆盖”而不是“Virtual”之外,类定义与工作副本相同。就好像E / F在propertyInfos上索引或不考虑的东西而不考虑propertyInfo.reflectytype
尝试改进#3
我可以使用界面来强制模式,但这不太优选,因为必须在每种类上声明界面,该界面开始看起来非常奇怪:
public class Franchise : SharedFranchiseIdBase, ISharedFranchiseId { ... }
public class FranchiseEntity : SharedFranchiseIdBase, ISharedFranchiseId { ... }
public class FranchiseMiscellaneous : SharedFranchiseIdBase, ISharedFranchiseId { ... }
.
huh?
是E / f中的一个错误,即它努力处理与派生类上的基类的属性相同?
为长时间啰嗦的解释道歉,这是今天早上整个调查的摘要。
解决方案
最后我决定采用手动解决方案,因为我无法获得任何改进的尝试。
代码和模型不优雅,但在一天结束时它执行OK。我在3个区域中实现了模式,它在域和SQL层中按要求执行。
为了缓解疼痛并为开发人员提供与此模式的一致方式,我创建了这个接口来强制执行所有关系:
public interface ISharedFranchiseId
{
FranchiseBilling Billing { get; set; }
FranchiseCompliance Compliance { get; set; }
FranchiseLeadAllocation LeadAllocation { get; set; }
FranchiseMessaging Messaging { get; set; }
FranchiseMiscellaneous Miscellaneous { get; set; }
FranchiseSignup Signup { get; set; }
}
.
因此,共享主键的每个模型都有这些属性(恼人的位):
public class FranchiseBilling/Compliance/etc : ISharedFranchiseId
{
// Properties implemented on this model
#region Navigations to other entities sharing primary key
public virtual FranchiseBilling Billing { get; set; }
public virtual FranchiseCompliance Compliance { get; set; }
public virtual FranchiseLeadAllocation LeadAllocation { get; set; }
public virtual FranchiseMessaging Messaging { get; set; }
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
public virtual FranchiseSignup Signup { get; set; }
#endregion
}
.
并通过FLUENT API配置如下(疼痛位):
// Franchise = the "primary/parent" model
public class FranchiseMapping : EntityTypeConfiguration<Franchise>
{
public FranchiseMapping()
{
HasRequired(x => x.Billing).WithRequiredPrincipal();
HasRequired(x => x.Compliance).WithRequiredPrincipal();
HasRequired(x => x.LeadAllocation).WithRequiredPrincipal();
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal();
HasRequired(x => x.Messaging).WithRequiredPrincipal();
HasRequired(x => x.Signup).WithRequiredPrincipal();
}
}
// Now each "child" model gets link to all the others. We only need links going one way,
// So each model links to the ones listed below.
// This makes it easy to implement an extra child model down the track as we just
// insert the configuration it here and copy from the next one.
public class FranchiseBillingMapping : EntityTypeConfiguration<FranchiseBilling>
{
public FranchiseBillingMapping()
{
Ignore(x => x.Billing);
HasRequired(x => x.Compliance).WithRequiredDependent(x => x.Billing);
HasRequired(x => x.LeadAllocation).WithRequiredPrincipal(x => x.Billing);
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal(x => x.Billing);
HasRequired(x => x.Messaging).WithRequiredPrincipal(x => x.Billing);
HasRequired(x => x.Signup).WithRequiredPrincipal(x => x.Billing);
}
}
public class FranchiseComplianceMapping : EntityTypeConfiguration<FranchiseCompliance>
{
public FranchiseComplianceMapping()
{
Ignore(x => x.Compliance);
HasRequired(x => x.LeadAllocation).WithRequiredPrincipal(x => x.Compliance);
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal(x => x.Compliance);
HasRequired(x => x.Messaging).WithRequiredPrincipal(x => x.Compliance);
HasRequired(x => x.Signup).WithRequiredPrincipal(x => x.Compliance);
}
}
public class FranchiseLeadAllocationMapping : EntityTypeConfiguration<FranchiseLeadAllocation>
{
public FranchiseLeadAllocationMapping()
{
Ignore(x => x.LeadAllocation);
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal(x => x.LeadAllocation);
HasRequired(x => x.Messaging).WithRequiredPrincipal(x => x.LeadAllocation);
HasRequired(x => x.Signup).WithRequiredPrincipal(x => x.LeadAllocation);
}
}
public class FranchiseeMiscellaneousMapping : EntityTypeConfiguration<FranchiseeMiscellaneous>
{
public FranchiseeMiscellaneousMapping()
{
Ignore(x => x.Miscellaneous);
HasRequired(x => x.Messaging).WithRequiredPrincipal(x => x.Miscellaneous);
HasRequired(x => x.Signup).WithRequiredPrincipal(x => x.Miscellaneous);
}
}
public class FranchiseMessagingMapping : EntityTypeConfiguration<FranchiseMessaging>
{
public FranchiseMessagingMapping()
{
Ignore(x => x.Messaging);
HasRequired(x => x.Signup).WithRequiredPrincipal(x => x.Messaging);
}
}
public class FranchiseSignupMapping : EntityTypeConfiguration<FranchiseSignup>
{
public FranchiseSignupMapping()
{
Ignore(x => x.Signup);
}
}
. 不隶属于 StackOverflow