实体框架:为 MYSQL 表生成自定义 ID
本文关键字:自定义 ID MYSQL 框架 实体 | 更新日期: 2023-09-27 18:34:46
我需要使用 MYSQL 表的实体框架生成一个自定义 ID(以字符串为前缀的数字序列(。以下示例说明了所需的内容
Id name
ACT-DT-1 Activity DT
ACT-Dx-1 Activity Dx
ACT-Dx-2 Activity Dx
ACT-DT-2 Activity DT
ACT-DT-3 Activity DT
因此,如果新记录是 ACT-Dx,则 ID 必须是 ACT-Dx-3,或者如果它是 ACT-DT,则 ID 必须是 ACT-DT-4,或者如果它有新的前缀,例如 ACT-Dg,则 ID 必须是 ACT-Dg-1。
我能采取的最佳方法是什么,
我建议你覆盖DbContext SaveChanges
方法。不确定这是否是最佳实践,但它在我的一个项目中有效。
原则是,当您向 dbContext 添加新实体时,您会分配值为 -1、-2、-3 等的假 ID。在执行调用方法时SaveChanges
这些假密钥将替换为正确的密钥值ReplaceIDs
。
这样做,您当然必须更新另一个相关实体中的引用。如果您将 foregn 键与主键命名不同,则可能会很棘手。我总是尝试为外键和主键使用相同的名称,不仅使用ID
,还使用ActivityID
。
这是一个快速修改的版本,希望它不包含错误。
public partial class MyDbContext
{
public override int SaveChanges()
{
// Other custom logic
ReplaceIDs();
}
/// <summary>
/// Replaces IDs with calculated values when saving
/// </summary>
private void ReplaceIDs()
{
Debug.Print("**************************************************************");
this.ObjectContext.DetectChanges();
foreach (var dbEntityEntry in ChangeTracker.Entries().Where(x => x.State == EntityState.Added))
{
Type t = GetEntityType(dbEntityEntry.Entity);
string baseTypeName = t.Name;
// Get the entity key name
var keyName = this.ObjectContext.MetadataWorkspace
.GetEntityContainer(this.ObjectContext.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets
.First(x => x.ElementType.Name.Equals(baseTypeName))
.ElementType
.KeyMembers
.Select(key => key.Name)
.FirstOrDefault();
string keyValue = null;
if (keyName!=null)
{
keyValue = dbEntityEntry.CurrentValues[keyName];
}
string newKey = null;
//Custom logic for ID replacement
if (t.Name.Equals("MyTable") && keyValue!= null)
{
string addedName = dbEntityEntry.CurrentValues["Name"];
int keyValueNumber;
if (keyValue.HasValue && Int32.TryParse(keyValue, out keyValueNumber) && keyValueNumber <= 0)
{
//Calculate shomehow the last value of your set of IDs
//I store last IDs for different sets in extra table, e.g. IDSets
var q = from x in this.IDSets where x.Name.Equals(addedName) && x.TableName.Equals("MyTable")
select x.LastID;
var lastKey = q.FirstOrDefault();
if (lastKey == null) throw new Exception("..."); //Handle somehow missing ID set, create new etc.
int? newID = null;
if (lastKey.LastID == null)
newID=1;
else
newID= lastKey.LastID;
newKey = string.Format("{0}-{1}",addedName,++newID);
lastKey.LastID = newID;
}
}
//Key replacement
if (newKey!=null)
{
int originalKey = (int)dbEntityEntry.CurrentValues[keyName];
dbEntityEntry.CurrentValues[keyName] = newKey;
Debug.Print("{0},{1} = {2} : {3}", baseTypeName, addedKontext, newKey, newIDWithKontext);
//Refresh references
string keyNameHelper=String.Format("{0}_", keyName);
foreach (var e in ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged))
{
Type tfix = e.Entity.GetType().BaseType;
foreach (var pname in e.CurrentValues.PropertyNames)
{
if ((pname.Equals(keyName) || pname.StartsWith(keyNameHelper)))
{
object o = e.CurrentValues[pname];
if (o!=null && o.GetType() == typeof(Int32) && ((int)o) == originalKey)
{
e.CurrentValues[pname] = newKey;
Debug.Print("FIX: {0},{1} = {2} >> {3}",tfix.Name, pname, originalKey, newKey);
}
}
}
}
}
}
this.ObjectContext.DetectChanges();
Debug.Print("**************************************************************");
}
public static Type GetEntityType(object entity)
{
if (entity == null)
return null;
if (IsProxy(entity))
return entity.GetType().BaseType;
else
return entity.GetType();
}