gpt4 book ai didi

c# - 在 linqtoSQL 中使用主键

转载 作者:行者123 更新时间:2023-11-30 17:14:04 25 4
gpt4 key购买 nike

我正在尝试编写一些通用的 linqtoSQL,它根据实体的主键对实体执行操作。我正在使用的一些实体具有复合主键。

从根本上说,我希望能够做这样的事情:

if( PrimaryKey(foo) == PrimaryKey(bar) ) ...

或者,

from oldEntity in oldTableOrCollection
join newEntity in newTableOrCollection
on PrimaryKeyOf(oldEntity) equals PrimaryKeyOf(newEntity)
select new {oldEntity, newEntity}

仅要求实体具有主键。

这是我目前发现的:

可以做这样的事情

var query = from row in oneTableOfRows
join otherRow in anotherTableOfRows on
new { row.Column1, row.Column2 }
equals
new { otherRow.Column1, otherRow.Column2}
select ...;

其中 linqtosql 将使用匿名类型进行比较(前提是属性名称匹配)。

然后我可以抽象出选择要连接的列的方法以允许通用行类型:

void DoQuery<RowType,KeyType>(Table<RowType> oneTableOfRows,
Table<RowType> anotherTableOfRows,
Func<RowType, KeyType> keySelector)
{
var query = from row in oneTableOfRow
join otherRow in anotherTableOfRows on
keySelector(row)
equals
keySelector(otherRow)
select ...;
}

...

Func<rowType, keyType> myKeySelector = row => new { row.Column1, row.Column2 };

DoQuery(table, otherTable, myKeySelector);

我现在正试图转移到 keySelector 将选择任何 RowType 的主键的地方。我正在使用基于 http://www.codeplex.com/l2st4 的自定义模板生成我的实体(它本身与 VS 中的默认值非常相似)。我希望理想地让每个生成的 RowType 能够选择从 dbml 收集的主键。到目前为止,输出如下所示:

public interface IPrimaryKeyEntity<PrimaryKeyType>
{
PrimaryKeyType PrimaryKey { get; }
}

//Here, Product is a table with composite primary key based on its ProductID and it's ProductPriceVersionID columns

//I've tried using both class and struct as the primary key type for entities
public class ProductPrimaryKey
{
public Guid ProductID;
public Guid ProductPriceVersionID;
}

public partial class Product : IPrimaryKeyEntity<ProductPrimaryKey>,
INotifyPropertyChanging, INotifyPropertyChanged
{
#region IPrimaryKeyEntity Implementation
public ProductPrimaryKey PrimaryKey
{
get
{ return new ProductPrimaryKey()
{
ProductID = this.ProductID,
ProductPriceVersionID = this.ProductPriceVersionID
};
}
}
#endregion

...
//Rest is mostly standard LinqToSql entity generation
}

回到最初的目标,我现在可以为我所有的主键实体编译以下内容:

from oldEntity in oldTableOrCollection
join newEntity in newTableOrCollection
on oldEntity.PrimaryKey equals newEntity.PrimaryKey
select new {oldEntity, newEntity}

但是,在运行时,我遇到了臭名昭著的 [PrimaryKey]“没有支持的 SQL 转换”异常。

我知道要转换为 SQL 必须使用 Expression,但是我对 Linq.Expressions 很不熟悉并且在尝试应用时没有任何进展它对我的情况...

如果有人可以改进我目前所掌握的内容或总体上有更好的方法,我将不胜感激....

干杯

最佳答案

问题是你在这里调用了一个函数:

在 oldEntity 上加入 ...。PrimaryKey 等于 newEntity。PrimaryKey

属性获取是一个函数调用。 Linq to SQL 不知道此函数,因此无法翻译它。

使这项工作有效的唯一方法是构建一个对应于此 SQL 的表达式:

        join otherRow in anotherTableOfRows on
new { row.Column1, row.Column2 }
equals
new { otherRow.Column1, otherRow.Column2}

没有别的办法,我可以向你保证。您可以这样做:首先,声明一个自定义元组类:

class CustomTuple2<T1,T2>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
}

您对所有可能的成员数(例如 8 或 16)执行此操作。

让我们看看如何转换连接:

IQueryable<T1> t1 = ...; //table 1
IQueryable<T2> t2 = ...; //table 2
var joined = t1.Join(t2, _t1 => _t1.Key, _t2 => _t2.Key);

lambda 参数是表达式。 您需要使用表达式树构建这两个表达式。这就是魔法!

例如第一个lambda:

var param = Expression.Parameter(typeof(T1), "_t1");
var key = Expression.Property(param, "Key");
var lambda1 = Expression.Lambda(param, key);

对第二个 lambda 执行相同的操作。 (请记住,这是伪代码。我不记得所有内容是如何调用的。)

最后,调用 Join:

var joined = typeof(Queryable).GetMethod("Join").Invoke(t1, t2, lambda1, lambda2);

这就是您在运行时构建连接的方式!请注意,所有这些都是伪代码。您需要进行一些研究才能找出 API 并使其正常工作,但您一定可以做到。

此外,如果您有一个复合键,您将需要提到的元组类来将键成员投影到其中。

关于c# - 在 linqtoSQL 中使用主键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9165015/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com