【问题标题】:Entity Framework adds duplicate foreign keys实体框架添加重复的外键
【发布时间】:2020-07-24 20:20:24
【问题描述】:

我有两个实体

public class CandlestickData
{
    [Key]
    public int Id { get; set; }
    public virtual Symbol Symbol { get; set; }
    [Column(TypeName = "datetime2")]
    public DateTime Time { get; set; }
    public decimal Open { get; set; }
    public decimal High { get; set; }
    public decimal Low { get; set; }
    public decimal Close { get; set; }
}

public class Symbol
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
}

因为我每分钟在数据库中添加大量“CandlestickData”,并且符号通常相同且不会更改,所以我想避免对数据库的无用调用,因此我创建了一个扩展方法来保留符号已经从列表中的数据库中检索到,所以我重新使用它们。

public static class Extension
    {
        static List<Symbol> ExistingSymbols = new List<Symbol>();
        public static Symbol GetSymbolIfExistsOrCreateItInTheDb(this string name, Repository repository)
        {
            if (ExistingSymbols.Any(x => x.Name == name))
            {
                return ExistingSymbols.First(x => x.Name == name);
            }
            if (repository.SymbolExists(name))
            {
                var symbol = repository.GetSymbol(name);
                ExistingSymbols.Add(symbol);
                return symbol;
            }
            else
            {
                Symbol symbol = new Symbol { Name = name };
                repository.AddSymbol(symbol);
                symbol = repository.GetSymbol(name);
                ExistingSymbols.Add(symbol);
                return symbol;
            }
        }
    }

这是在数据库中添加多个“CandlestickData”的代码

using (var repository = new Repository())
            {
                var candlesticks = new List<CandlestickData>();
                foreach (var symbol in AllSymbolsTradeData[GetNotUsedIndex()])
                {
                    candlesticks.Add(new CandlestickData
                    {
                        Close = symbol.Value.Close,
                        Symbol = symbol.Key.GetSymbolIfExistsOrCreateItInTheDb(repository),
                        High = symbol.Value.High,
                        Low = symbol.Value.Low,
                        Open = symbol.Value.Open,
                        Time = symbol.Value.Time
                    });
                }
                repository.AddCandlesticksData(candlesticks);
                repository.CommitChanges();
            }

如果您想查看 Repository 类的外观:

public class Repository : IDisposable
    {
        private Db context;
        public Repository()
        {
            context = new Db();
        }

        public bool SymbolExists(string name)
        {
            return context.Symbols.Where(x => x.Name == name).Any();
        }
        public Symbol GetSymbol(string name)
        {
            return context.Symbols.First(x => x.Name == name);
        }
        public void AddSymbol(Symbol symbol)
        {
            context.Symbols.Add(symbol);
            context.SaveChanges();
        }
        public void AddCandlestickData(CandlestickData candlestickData)
        {
            context.Candlesticks.Add(candlestickData);
        }
        public void AddCandlesticksData(List<CandlestickData> candlesticks)
        {
            context.Candlesticks.AddRange(candlesticks);
        }

        public void CommitChanges()
        {
            context.SaveChanges();
        }

        public void Dispose()
        {
            context.Dispose();
        }
    }

现在我的问题是,每次在调用 CommitChanges 方法后,我的 Extension 方法从内存列表(带有 ID 和名称)中获取符号时,从我的列表中使用的参考符号获取另一个 ID,并且在数据库中插入新符号​​,名称相同,但具有新 ID。

当我每次都从数据库中获取符号时,我的代码工作正常(没有在数据库中创建重复项),但我找不到我做错了什么,因为存储在列表中的符号是来自db 具有正确的 ID...

【问题讨论】:

    标签: c# sql-server entity-framework-6


    【解决方案1】:

    问题是 ExistingSymbols 被加载到与保存烛台的上下文不同的 DbContext 中。

    这是因为ExistingSymbols 是静态的,它用于保存烛台的多个操作。

    您可以通过更改CandlestickData 的模型以添加外键来解决它:

    public class CandlestickData
    {
    
        public int SymbolId { get; set; }
    
        [ForeignKey(nameof(SymbolId))]
        public virtual Symbol Symbol { get; set; }
    

    然后在使用符号创建新对象时只使用外键:

    candlesticks.Add(new CandlestickData
    {
        Close = symbol.Value.Close,
        SymbolId = symbol.Key.GetSymbolIfExistsOrCreateItInTheDb(repository).Id,
        High = symbol.Value.High,
        Low = symbol.Value.Low,
        Open = symbol.Value.Open,
        Time = symbol.Value.Time
    });
    

    【讨论】:

    • 您知道避免这种情况的其他解决方案吗?除了在应用程序的生命周期中使用相同的 dB 上下文
    猜你喜欢
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多