Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为LINQ到SQL编写Upsert?_Linq_Linq To Sql - Fatal编程技术网

如何为LINQ到SQL编写Upsert?

如何为LINQ到SQL编写Upsert?,linq,linq-to-sql,Linq,Linq To Sql,因此,我想为LINQ to SQL编写一个通用的Upsert函数,但在概念化如何执行时遇到了一些问题。我希望它能像这样工作: var db = new DataContext(); db.Customers.UpsertOnSubmit(customer); 所以它必须在某种程度上是通用的,我猜是表上的扩展方法。在确定基础表的主键时,我已经做到了这一点: var context = source.Context; var table = context.Mapping.GetTable(sou

因此,我想为LINQ to SQL编写一个通用的Upsert函数,但在概念化如何执行时遇到了一些问题。我希望它能像这样工作:

var db = new DataContext();
db.Customers.UpsertOnSubmit(customer);
所以它必须在某种程度上是通用的,我猜是表上的扩展方法。在确定基础表的主键时,我已经做到了这一点:

var context = source.Context;
var table = context.Mapping.GetTable(source.GetType());
var primaryMember = table.RowType.DataMembers.SingleOrDefault(m => m.IsPrimaryKey);

我假设有必要用它来组成一个查询,以判断该项是否已经在数据库中,但此时我真的不知道该如何处理它。

我做了类似的事情,但方法不同。每个实体都实现了
ienty
。如果对象是新的或现有的,
IEntity
的属性之一是状态。然后,我为每个实体实现该功能,如:

public EntityState EntityState
{
    get
    {
        if (_Id > 0)
            return EntityState.Exisiting;
        else
            return EntityState.New;
    }
}
然后,泛型
Upsert
可以是(在泛型存储库类型类上):

public虚拟空向上插入(Ta实体)
助教:在哪里上课
{
如果(!(实体为实体))
抛出新异常(“T必须是IEntity类型”);
if(((entity)entity).EntityState==EntityState.Exisiting)
GetTable().Attach(实体,true);
其他的
GetTable().InsertOnSubmit(实体);
}
private System.Data.Linq.Table GetTable()
助教:在哪里上课
{
返回_dataContext.Context.GetTable();
}

如果您从另一个datacontext进行附加,请确保您的对象上有时间戳。

简短回答:

抓住这个:

解释

要在LINQtoSQL中执行UPSERT而不首先查询记录,可以执行以下操作。它仍然会点击数据库一次,以检查记录是否存在,但不会拉取记录:

var blob = new Blob { Id = "some id", Value = "some value" }; // Id is primary key (PK)

if (dbContext.Blobs.Contains(blob)) // if blob exists by PK then update
{
    // This will update all columns that are not set in 'original' object. For
    // this to work, Blob has to have UpdateCheck=Never for all properties except
    // for primary keys. This will update the record without querying it first.
    dbContext.Blobs.Attach(blob, original: new Blob { Id = blob.Id });
}
else // insert
{
    dbContext.Blobs.InsertOnSubmit(blob);
}
dbContext.Blobs.SubmitChanges();
扩展方法

我为它想出了以下扩展方法

public static class EntityExtensionMethods
{
    public static void InsertOrUpdateOnSubmit<TEntity>(this Table<TEntity> table, TEntity entity, TEntity original = null)
        where TEntity : class, new()
    {
        if (table.Contains(entity)) // if entity exists by PK then update
        {
            if (original == null)
            {
                // Create original object with only primary keys set
                original = new TEntity();
                var entityType = typeof(TEntity);
                var dataMembers = table.Context.Mapping.GetMetaType(entityType).DataMembers;
                foreach (var member in dataMembers.Where(m => m.IsPrimaryKey))
                {
                    var propValue = entityType.GetProperty(member.Name).GetValue(entity, null);
                    entityType.InvokeMember(member.Name, BindingFlags.SetProperty, Type.DefaultBinder,
                        original, new[] {propValue});
                }
            }

            // This will update all columns that are not set in 'original' object. For
            // this to work, entity has to have UpdateCheck=Never for all properties except
            // for primary keys. This will update the record without querying it first.
            table.Attach(entity, original);
        }
        else // insert
        {
            table.InsertOnSubmit(entity);
        }
    }
}

我在这个要点中添加了更多的扩展方法:

好吧。。。upsert的全部要点是,您不知道它是否存在,您只希望数据库具有新内容;upsert将为您保存“额外往返”以确定该值。你的解决方案不能回答这个问题;需要的是一个sql
合并,如下所述:。这个答案适用于实体框架。有关LINQ到SQL解决方案,请参见我的答案。
public static class EntityExtensionMethods
{
    public static void InsertOrUpdateOnSubmit<TEntity>(this Table<TEntity> table, TEntity entity, TEntity original = null)
        where TEntity : class, new()
    {
        if (table.Contains(entity)) // if entity exists by PK then update
        {
            if (original == null)
            {
                // Create original object with only primary keys set
                original = new TEntity();
                var entityType = typeof(TEntity);
                var dataMembers = table.Context.Mapping.GetMetaType(entityType).DataMembers;
                foreach (var member in dataMembers.Where(m => m.IsPrimaryKey))
                {
                    var propValue = entityType.GetProperty(member.Name).GetValue(entity, null);
                    entityType.InvokeMember(member.Name, BindingFlags.SetProperty, Type.DefaultBinder,
                        original, new[] {propValue});
                }
            }

            // This will update all columns that are not set in 'original' object. For
            // this to work, entity has to have UpdateCheck=Never for all properties except
            // for primary keys. This will update the record without querying it first.
            table.Attach(entity, original);
        }
        else // insert
        {
            table.InsertOnSubmit(entity);
        }
    }
}
var blob = new Blob { Id = "some id", Value = "some value" }; // Id is primary key (PK)
dbContext.Blobs.InsertOrUpdateOnSubmit(blob);
dbContext.Blobs.SubmitChanges();