C# EntityFramework首先使用数据库检测复杂类型

C# EntityFramework首先使用数据库检测复杂类型,c#,database,entity-framework,C#,Database,Entity Framework,我们正在使用EntityFramework,并且已经经历了一段数据库优先的漫长旅程。我们有多个上下文和很多很多实体。当我们接受先进行代码项目的概念时,我们希望探索EF可用的替代可能性 我们目前使用的是最新版本的EF,即6.0.2 我们有很多带有公共字段的表,比如审计字段“CreatedBy”、“CreatedDate”、“UpdatedBy”和“UpdatedDate”,我们认为在这里使用ComplexType是完美的 在使用这些字段的表中,当我们从数据库生成代码时,它会将字段拉入原始状态。然后

我们正在使用EntityFramework,并且已经经历了一段数据库优先的漫长旅程。我们有多个上下文和很多很多实体。当我们接受先进行代码项目的概念时,我们希望探索EF可用的替代可能性

我们目前使用的是最新版本的EF,即6.0.2

我们有很多带有公共字段的表,比如审计字段“CreatedBy”、“CreatedDate”、“UpdatedBy”和“UpdatedDate”,我们认为在这里使用ComplexType是完美的

在使用这些字段的表中,当我们从数据库生成代码时,它会将字段拉入原始状态。然后在模型浏览器中删除它,添加复杂类型,然后将复杂属性映射到数据库中的字段名

在这个实验中,我们运行“从模型生成数据库”而不映射字段,以查看生成的列名是什么,以及是否有任何约定或自动魔法允许双向行为(将复杂类型转换为列,并将列识别为复杂类型)

这导致列名的复杂类型后缀为“\u1”和字段名。我们进行了测试,当我们重新生成模型时,它没有从模型中的数据库中提取复杂类型

有没有合适的方法让EF先用数据库检测表中的复杂类型? 是否有我可以编写的代码工厂、生成器、策略或模板

我们的主要动机是,我们需要支持大量的表,我们接受频繁的更改,我们希望防止团队中的人员忽视这一步骤并破坏代码基础

非常感谢您的时间和热情

--编辑--

虽然使用复杂类型的自动检测并不能解决问题,但这解决了开发人员在每次运行T4模板更新时破坏模型的问题

我所做的是EF上的通用半存储库模式。我还使用了intefaces,允许识别和自动使用匹配的方法

可审核接口:

public interface IDbAuditable : IDbEntity
{
    Guid CreatedById { get; set; }
    DateTime CreatedOn { get; set; }
    Guid ModifiedById { get; set; } 
    DateTime ModifiedOn { get; set; }
    Guid? DeletedById { get; set; } 
    DateTime? DeletedOn { get; set; } 
}
(我个人喜欢这样的想法,如果CreatedOn==ModifiedOn,那么它就从来没有被修改过,有些人喜欢DateTime?,其实他们的目的是一样的,这并不重要。)

因为这个例子在一个小项目中,所以我只是包装了EF上下文,没有使用任何IoC/DI。这是所有实际代码的一小部分(有些方法缺失,有些接口缺失,但应该是完全合理的)

公共密封类MyDb:IDisposable
{
私有MyContext_上下文;
公共MyDb(字符串连接字符串,惰性currentUserIdFunc)
{
此._context=newmycontext(connectionString);
SetInitializer(新的DatabaseInitializer());
此.u context.Database.Initialize(true);
这是。_currentUserIdFunc=currentUserIdFunc;
}
公共异步任务GetEntityAsync(Func entityQuery),其中T:class,IDbEntity
{
var query=entityQuery(this.\u context.Set());
如果(类型(T)可审核)
{
query=query.Cast()
.Where(a=>!a.DeletedById.HasValue)
.Cast();
}
返回wait query.FirstOrDefaultAsync();
}
公共异步任务UpdateAsync(T实体),其中T:class,IDbEntity
{
if(实体为IDbDoNotModify)
{
抛出新的DoNotModifyException(“无法修改实体(IDoNotModify)”;
}
此.u context.Set().Attach(实体);
var entry=此._context.entry(实体);
entry.State=EntityState.Unchanged;
var entityType=entity.GetType();
var metadata=entityType.GetCustomAttributes(typeof(MetadataTypeAttribute)).FirstOrDefault()作为MetadataTypeAttribute;
if(元数据!=null)
{
var type=metadata.MetadataClassType;
var properties=type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.选择(p=>new
{
名称=p.名称,
ScaffoldColumn=p.GetCustomAttributes(typeof(ScaffoldColumnAttribute),true),
Readonly=entityType.GetProperty(p.Name).GetCustomAttributes(typeof(ReadOnlyAttribute),true).FirstOrDefault()作为ReadOnlyAttribute
})
.其中(p=>(p.ScaffoldColumn==null | | p.ScaffoldColumn.Scaffold)
&&(p.Readonly==null | |!p.Readonly.IsReadOnly))
.ToList();
foreach(属性中的var属性)
{
entry.Property(Property.Name).IsModified=true;
}
}
其他的
{
entry.State=EntityState.Modified;
}
var auditable=可审计实体;
if(可审核!=null)
{
this.Modified(可审核,this.\u currentUserIdFunc.Value);
entry.Property(“ModifiedOn”).IsModified=true;
entry.Property(“ModifiedById”).IsModified=true;
}
return等待此消息。_context.savechangesync();
}
已修改私有void(IDBAditable实例,Guid?currentUserId)
{
instance.ModifiedById=currentUserId.Value;
instance.ModifiedOn=DateTime.Now;
}
}
以下是我将如何使用它:

// returns the first car with a model of ford
var car = MyDb.EntityAsync<Car>((query) = query
  .Where(c => c.Model.Equals("ford")
);

// returns the first dog with an ownerId of id
var car = MyDb.EntityAsync<Dog>((query) => query
  .Where(d => d.OwnerId == Id)
);

UpdateAsync(car);
//返回第一辆福特车型的汽车
var car=MyDb.EntityAsync((查询)=查询
其中(c=>c.Model.Equals(“福特”)
);
//返回第一个所有者id为id的狗
var car=MyDb.EntityAsync((查询)=>query
.Where(d=>d.OwnerId==Id)
);
更新同步(car);
这个示例应用程序非常小,因此我没有实现任何UnitOfWork,但可以针对这种情况轻松修改它。此外,如果有多个
// returns the first car with a model of ford
var car = MyDb.EntityAsync<Car>((query) = query
  .Where(c => c.Model.Equals("ford")
);

// returns the first dog with an ownerId of id
var car = MyDb.EntityAsync<Dog>((query) => query
  .Where(d => d.OwnerId == Id)
);

UpdateAsync(car);