c# - Entity Framework : Generate custom Id for MYSQL table

标签 c# mysql entity-framework

我需要使用 MYSQL 表的 Entity Framework 生成自定义 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< 时,这些假键会被正确的键值替换。/code> 调用 ReplaceIDs 方法。

执行此操作时,您当然必须更新其他相关实体中的引用。如果您的外键名称与主键名称不同,这可能会很棘手。我总是尝试使外键和主键具有相同的名称,而不是仅使用 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();
    }

关于c# - Entity Framework : Generate custom Id for MYSQL table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27584055/

相关文章:

c# - 未找到与请求 URI 匹配的操作

c# - 将所有首字母转换为大写,每个单词的首字母小写

c# - 使用 C# 将 XML 转换为 MySQL

mysql - 从linux终端插入mysql

php - 生成并分离 PHP 进程而不共享任何数据库资源以便子进程可以退出?

c# - 如何在 VB.NET 中使用以下用 C# 编写的事件/委托(delegate)?

mysql - 为什么 MariaDB-10.2.8 UNHEX() 返回 NULL?

entity-framework - 如何在 Entity Framework 中使用内部联接删除或更新?

c# - 主键始终插入零

entity-framework - Entity Framework 代码优先空外键