Min*_*Min 5 c# database entity-framework
我们正在使用EntityFramework并且已经使用Database First进行了长途旅行.我们有多个上下文和许多实体.虽然我们接受了首先进行代码项目的概念,但我们希望探索EF可用的其他可能性.
我们正在使用最新版本的EF,当前版本为6.0.2
我们有很多常用字段的表,例如审计字段"CreatedBy","CreatedDate","UpdatedBy"和"UpdatedDate",我们认为在这里使用ComplexType是完美的.
在使用这些字段的表中,当我们从数据库生成代码时,它会以raw格式提取字段.然后,我们在模型浏览器中删除它,添加复杂类型,然后将复杂属性映射到DB中的字段名称.
在这个实验中,我们运行"从模型生成数据库"而不映射字段以查看结果列名称是什么,以及任何约定或自动魔术是否允许双向行为(将复杂类型转换为列并将列识别为复杂的类型).
这导致列名称的复杂类型后缀为"_"和字段名称.我们进行了测试,当我们重新生成模型时,它没有从模型中的数据库中拉出复杂类型.
有没有一种正确的方法让EF先检测具有数据库的表中的复杂类型?我可以编写一些代码工厂,构建器,策略或模板吗?
我们的主要动机是我们有很多表可以支持,我们接受频繁的更改,我们希望阻止团队中的人忽略这一步并打破代码库.
非常感谢StackOverflowians的时间!
- 编辑 -
虽然这并没有解决使用复杂类型的自动检测的问题,但这解决了Developer在每次运行T4模板更新时破坏模型的问题.
我所做的是基于 EF 的通用半存储库模式。我还使用接口来允许识别和自动使用方法(如果它们匹配)。
可审计接口:
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; }
}
Run Code Online (Sandbox Code Playgroud)
(我个人喜欢这样的想法:如果 CreatedOn == ModifiedOn 那么它就从未被修改过,有些人喜欢 DateTime?,它们服务于相同的目的并不重要。)
由于这个例子是在一个小项目中,所以我只是包装了 EF Context,没有使用任何 IoC/DI。这是所有实际代码的一小部分(缺少一些方法和一些接口,但它应该很有意义)。
public sealed class MyDb : IDisposable
{
private MyContext _context;
public MyDb(string connectionString, Lazy<Guid?> currentUserIdFunc)
{
this._context = new MyContext(connectionString);
Database.SetInitializer<MyContext>(new DatabaseInitializer());
this._context.Database.Initialize(true);
this._currentUserIdFunc = currentUserIdFunc;
}
public async Task<T> GetEntityAsync<T>(Func<IQueryable<T>, IQueryable<T>> entityQuery) where T : class, IDbEntity
{
var query = entityQuery(this._context.Set<T>());
if (typeof(T) is IDbAuditable)
{
query = query.Cast<IDbAuditable>()
.Where(a => !a.DeletedById.HasValue)
.Cast<T>();
}
return await query.FirstOrDefaultAsync();
}
public async Task<int> UpdateAsync<T>(T entity) where T : class, IDbEntity
{
if (entity is IDbDoNotModify)
{
throw new DoNotModifyException("Entity cannot be Modified (IDoNotModify).");
}
this._context.Set<T>().Attach(entity);
var entry = this._context.Entry<T>(entity);
entry.State = EntityState.Unchanged;
var entityType = entity.GetType();
var metadata = entityType.GetCustomAttributes(typeof(MetadataTypeAttribute)).FirstOrDefault() as MetadataTypeAttribute;
if (metadata != null)
{
var type = metadata.MetadataClassType;
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(p => new
{
Name = p.Name,
ScaffoldColumn = p.GetCustomAttributes(typeof(ScaffoldColumnAttribute), true).FirstOrDefault() as ScaffoldColumnAttribute,
Readonly = entityType.GetProperty(p.Name).GetCustomAttributes(typeof(ReadOnlyAttribute), true).FirstOrDefault() as ReadOnlyAttribute
})
.Where(p => (p.ScaffoldColumn == null || p.ScaffoldColumn.Scaffold)
&& (p.Readonly == null || !p.Readonly.IsReadOnly))
.ToList();
foreach (var property in properties)
{
entry.Property(property.Name).IsModified = true;
}
}
else
{
entry.State = EntityState.Modified;
}
var auditable = entity as IDbAuditable;
if (auditable != null)
{
this.Modified(auditable, this._currentUserIdFunc.Value);
entry.Property("ModifiedOn").IsModified = true;
entry.Property("ModifiedById").IsModified = true;
}
return await this._context.SaveChangesAsync();
}
private void Modified(IDbAuditable instance, Guid? currentUserId)
{
instance.ModifiedById = currentUserId.Value;
instance.ModifiedOn = DateTime.Now;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我将如何使用它:
// 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);
Run Code Online (Sandbox Code Playgroud)
这个示例应用程序非常小,因此我没有实现任何 UnitOfWork,但可以针对这种情况轻松修改它。此外,如果您有多个上下文,该类可以很容易地MyDb变成 a 。MyDb<T>我允许大量使用 DataAnnotations。
| 归档时间: |
|
| 查看次数: |
1137 次 |
| 最近记录: |