我需要使用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。
我可以采取的最佳方法是什么,
答案 0 :(得分:0)
我建议您覆盖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();
}