仅保存数据库表

时间:2017-11-02 21:29:54

标签: c# sql-server entity-framework

我的EF实体类看起来像:

public class DataPoint
{
    public int DataPointId {get; set;}
    public DateTime DateTime {get; set;}
    public double Value {get; set;}
}

其中DataPointId是PK,当时没有其他列被编入索引。

假设我们有一个DataPoints集合,必须将其添加到context.DataPoints数据库表中:

var dpToAdd = new List<DataPoint>{ /* 10000 different dp's */ };

但是,我想在db中只保存DataPoint'sDateTime时唯一的DataPoint列。 例如:dpToAdd中的DateTime = 01/01/2016 00:00:00之一有context.DataPoints - 如果DateTime已包含具有相同context.DataPoints值的DataPoint,则应忽略此点。

DateTime表可以有100万条记录,并且在单个请求中可以收集10-50k条记录,需要在保存到db之前进行验证。

如何处理这样的过程以使性能最佳?

我的第一个问题是在DataPoints列上创建一个索引,然后,对于即将添加的每个foreach (var dp in dpToAdd) { // with Any() if !(context.DataPoints.Any(p => p.DateTime == dp.DateTime)) { context.DataPoints.Add(dp); } // or with Contains() if !(context.DataPoints.Select(p => p.DateTime).Contains(dp.DateTime)) { context.DataPoints.Add(dp); } } ,请检查以下内容:

1:简单地循环遍历所有积分并检查需要添加的内容

DateTime

2:获取已在数据库中出现的var common = context.DataPoints.Select(p => p.DateTime).Intersect(dpToAdd.Select(d => d.DateTime)); var reallyToAdd = dpToAdd.Where(p => !common.Contains(p.DateTime)); context.DataPoints.AddRange(reallyToAdd); 值,并将其从db addition

中排除
conda update conda

如果可以通过任何其他更好的方式开发此任务,您还有其他任何建议吗?

2 个答案:

答案 0 :(得分:1)

如果您确实要插入如此大的表和大数据,出于性能原因,您应该使用相同的列加DataPointHelper创建帮助中间表Guid。首先,您将向此表插入数据,然后从DataPoints表中获取不存在的行,然后将它们插入DataPoints事务性正确性需要Guid属性:

var guid = Guid.NewGuid();
var data = dpToAdd.Select(x => new DataPointHelper 
{
    DateTime = x.DateTime,
    Value = x.Value,
    Guid = guid
}).ToList();
context.DataPointHelpers.AddRange(data);//it is better to use BulkInsert
context.SaveChanges();

var toInsert = (from x in context.DataPointHelpers
                where x.Guid == guid
                join y in context.DataPoints on x.DateTime equals y.DateTime into subs
                from sub in subs.DefaultIfEmpty()
                where sub == null
                select x.DateTime).ToList();

if(toInsert.Count > 0)
{
    var toInsertData = dpToAdd.Where(x => toInsert.Contains(x.DateTime)).ToList();
    context.DataPoints.AddRange(toInsertData);
    context.SaveChanges();
}

当然,您应该在两个表中为DateTime属性创建唯一索引。

因此,您只有三次往返数据库而不是数千次,或者不执行where DateTime in (thousands values)之类的查询,而且in语句有限制。

答案 1 :(得分:-1)

我认为你可以使用它:

var dt = DateTime.Now;
    var ls = new List<DataPoint>();
    ls.Add(new DataPoint { DataPointId =1, Value = 1, DateTime = dt});
    ls.Add(new DataPoint { DataPointId =2, Value = 2, DateTime = dt});
    ls.Add(new DataPoint { DataPointId =1, Value = 1, DateTime = DateTime.Now.AddDays(1)});

    var distincData = ls.GroupBy(l => l.DateTime).Select(g => g.First());