Entity Framework 添加重复的外键
Entity Framework adds duplicate foreign keys
我有两个实体
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;
}
}
}
这是在 db
中添加多个 '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();
}
此外,如果您想查看存储库 class 的外观:
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 方法后从内存列表(带有 ID 和名称)中获取符号时,从我的列表中使用的引用符号都会获取另一个 ID,并且在数据库插入一个具有相同名称但具有新 ID 的新符号。
当我每次都从数据库中获取符号时,我的代码工作正常(没有在数据库中创建重复项)并且我找不到我做错了什么,因为存储在列表中的符号就是那些来自具有正确 ID 的数据库...
问题是 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
});
我有两个实体
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;
}
}
}
这是在 db
中添加多个 '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();
}
此外,如果您想查看存储库 class 的外观:
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 方法后从内存列表(带有 ID 和名称)中获取符号时,从我的列表中使用的引用符号都会获取另一个 ID,并且在数据库插入一个具有相同名称但具有新 ID 的新符号。
当我每次都从数据库中获取符号时,我的代码工作正常(没有在数据库中创建重复项)并且我找不到我做错了什么,因为存储在列表中的符号就是那些来自具有正确 ID 的数据库...
问题是 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
});