C# 在LINQ to SQL中查找或创建对象的通用方法?

C# 在LINQ to SQL中查找或创建对象的通用方法?,c#,linq,linq-to-sql,C#,Linq,Linq To Sql,在我的代码中,我经常需要“查找或创建”这样的实体: var invoiceDb = ctx.Invoices.FirstOrDefault(a => a.InvoicerId == InvoicerId && a.Number == invoiceNumber); if (invoiceDb == null) { invoiceDb = new Invoice();

在我的代码中,我经常需要“查找或创建”这样的实体:

var invoiceDb = ctx.Invoices.FirstOrDefault(a => a.InvoicerId == InvoicerId &&
                                                 a.Number == invoiceNumber);
if (invoiceDb == null)
{
    invoiceDb = new Invoice();
    invoiceDb.Number = invoiceNumber;
    ctx.Invoices.InsertOnSubmit(invoiceDb);
}

我希望这是一个通用的方法。。。有什么好主意吗?

可以缩短为

if(invoiceDb == null) ctx.Invoices.InsertOnSubmit(invoiceDB = new Invoice() {Number = invoiceNumber});
你可以使用


我提出了这些扩展方法,似乎对我很有效

    public static T FindOrCreate<T>(this Table<T> table, Func<T, bool> find, Action<T> create) where T : class, new()
    {
        T val = table.FirstOrDefault(find);
        if (val == null)
        {
            val = new T();
            create(val);
            table.InsertOnSubmit(val);
        }
        return val;
    }

    public static T FindOrCreate<T>(this Table<T> table, Func<T, bool> find) where T : class, new()
    {
        return FindOrCreate(table, find, a => { });
    }


使用这样的扩展方法如何:

    var invoiceDb = ctx.Invoices.FindOrCreate(a => a.InvoicerId == InvoicerId &&
                                                     a.Number == invoiceNumber);
    invoiceDb.Number = invoiceNumber;
public static T FirstOrCreate<T>(this IEnumerable<T> source) where T : class, new()
{
    var result = source.FirstOrDefault();
    return result != null ? result : new T();
}
…或使用谓词:

Invoice selectedInvoice = db.Invoices.FirstOrCreate(i => i.ID == invoiceID);
将返回匹配的实体或新的(非空)实体

编辑:我今天一直在考虑这个问题,我突然想到,上面的内容要求您检测实体是新的(不存在),并将其附加到DataContext,因此我使用相同的方法提出了这个折衷方案:

public static T FirstOrCreate<T>(this IEnumerable<T> source, DataClassesDataContext db) where T : class, new()
{
    var result = source.FirstOrDefault();
    if (result == null)
    {
        result = new T();
        db.GetTable<T>().InsertOnSubmit(result);
    }
    return result;
}
肯定有一票赞成吗?:)

VB.NET版本:

Module dbi
    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean), _
        ByVal create As Action(Of T)) _
        As T

        Dim val As T = table.FirstOrDefault(find)
        If val Is Nothing Then
            val = New T()
            create(val)
            table.InsertOnSubmit(val)
        End If
        Return val
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean)) _
        As T

        Return FindOrCreate(table, find, Function(a))
    End Function

End Module
模块dbi
_
公共函数FindOrCreate(_
T的{Class,New})(ByVal表作为Data.Linq.table(T的)_
ByVal find As Func(属于T,布尔)_
ByVal创建为动作(T的))_
As T
Dim val As T=表。FirstOrDefault(查找)
如果瓦尔什么都不是
val=新的T()
创建(val)
表.InsertOnSubmit(val)
如果结束
返回值
端函数
_
公共函数FindOrCreate(_
T的{Class,New})(ByVal表作为Data.Linq.table(T的)_
ByVal find As Func(属于T,布尔))_
As T
返回FindOrCreate(表、查找、函数(a))
端函数
端模块

但是,这不会将新发票添加到表中。另请参见:(我编写了该文章的第一个版本,因此我会尽可能链接它)仍然需要逻辑来确定是否需要插入,但invoiceDb没有真正分配?因为我没有给你一个完整的可粘贴的代码示例而投反对票?它的目的是向您展示如何做,而不是为您做。这将始终在实体上设置“Number”属性,将其标记为dirty。在执行SubmitChanges()时,这可能/将为您提供不必要的更新
Invoice selectedInvoice = (from i in Invoices
                           where i.ID == invoiceID
                           select i).FirstOrCreate();
Invoice selectedInvoice = db.Invoices.FirstOrCreate(i => i.ID == invoiceID);
public static T FirstOrCreate<T>(this IEnumerable<T> source, DataClassesDataContext db) where T : class, new()
{
    var result = source.FirstOrDefault();
    if (result == null)
    {
        result = new T();
        db.GetTable<T>().InsertOnSubmit(result);
    }
    return result;
}
Customer selectedCustomer = (from c in db.Customers
                             where c.CustomerId == selectedCustomerId
                             select c).FirstOrCreate(db);
Module dbi
    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean), _
        ByVal create As Action(Of T)) _
        As T

        Dim val As T = table.FirstOrDefault(find)
        If val Is Nothing Then
            val = New T()
            create(val)
            table.InsertOnSubmit(val)
        End If
        Return val
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean)) _
        As T

        Return FindOrCreate(table, find, Function(a))
    End Function

End Module