C# 匹配两个项目列表的LINQ查询
我的问题是,我有一个来自实体框架的属性作为“attribute”。 所以我检索这个对象,它有一个属性标签列表,它们可以通过C# 匹配两个项目列表的LINQ查询,c#,asp.net,linq,entity-framework,C#,Asp.net,Linq,Entity Framework,我的问题是,我有一个来自实体框架的属性作为“attribute”。 所以我检索这个对象,它有一个属性标签列表,它们可以通过attribute.AttributeTags访问。现在我有了一个asp:TextBox,用户可以在其中编辑、删除和添加新标记(逗号分隔)。(在页面加载时,我正在将属性标记添加到此文本框) 在页面上回发后,我返回用户输入并将其拆分为字符串数组,并将其存储在名为AttributeTags的变量中 现在,我想添加未包含在EF原始属性列表中的新标记,并想删除属性中包含但未在用户输入
attribute.AttributeTags
访问。现在我有了一个asp:TextBox
,用户可以在其中编辑、删除和添加新标记(逗号分隔)。(在页面加载时,我正在将属性标记添加到此文本框
)
在页面上回发后,我返回用户输入并将其拆分为字符串数组,并将其存储在名为AttributeTags
的变量中
现在,我想添加未包含在EF原始属性
列表中的新标记,并想删除属性
中包含但未在用户输入字符串数组属性标签
中找到的标记
我正在做这样的事情:
BusinessObjects.Attribute attribute = db.Attributes.FirstOrDefault(a => a.attribute_id == AttributeID);
string[] AttributeTags = txtAttributeTags.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in AttributeTags)
{
if (!attribute.AttributeTags.Any(t => t.value == item))
{
AttributeTag tag = new AttributeTag { value = item, timestamp = DateTime.Now };
attribute.AttributeTags.Add(tag);
}
else
{
AttributeTag tag = attribute.AttributeTags.FirstOrDefault(t => t.value == item);
}
}
但我有点被困在这里,因为我对LINQ和EF是相当陌生的。使用db对象属性上的Remove方法,然后保存更改
db.Attributes.Remove( object );
然后保存对db对象的更改
如果我正确地假设您的db对象是EF中连接的对象,那么这应该是可行的。我无法进行完整的测试,但是沿着这些思路应该可以做到:
BusinessObjects.Attribute attribute = db.Attributes.FirstOrDefault(a => a.attribute_id == AttributeID);
string[] AttributeTags = txtAttributeTags.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in from a in AttributeTags
where attribute.AttributeTags.Any(t => t.value == a)
select new AttributeTag
{
value = item,
timestamp = DateTime.Now
})
attribute.AttributeTags.Add(item);
foreach (var item in from a in attribute.AttributeTags
where AttributeTags.Any(t => t == a.value)
select a)
attribute.AttributeTags.Remove(item);
db.SaveChanges();
对于这种情况,我有两种解决方案
第一种解决方案
我们可以使用
方法创建一个例外,该方法将允许我们删除i集合
中已经在给定一个IEnumerable
中的所有项。该方法的代码如下所示:
public static int ExceptWith<TItem>
(
this ICollection<TItem> collection,
IEnumerable<TItem> other
)
{
if (ReferenceEquals(collection, null))
{
throw new ArgumentNullException("collection");
}
else if (ReferenceEquals(other, null))
{
throw new ArgumentNullException("other");
}
else
{
int count = 0;
foreach (var item in other)
{
while (collection.Remove(item))
{
count++;
}
}
return count;
}
}
您可以这样做:
var AttributeTags =
new List<string>
(
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
)
);
现在您可以执行以下操作:
AttriuteTags.ExceptWith(existingTags);
由于attribute.AttributeTag的类型不是IEnumerable
,因此使用选择:
AttriuteTags.ExceptWith(attribute.AttributeTag.Select(item => item.value));
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value)
);
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value),
new CustomEqualityComparer<string>
(
(a, b) => 1, //your custom comparison here
str => str.GetHashCode()
)
);
这只会在列表中留下新标签
注意:此方法取决于Remove的实现,如果您需要进行特殊比较,那么使用此方法就不走运了
第二种解决方案
还有另一种方法。您可以使用可枚举
类中的
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except(existingTags);
由于attribute.AttributeTag的类型不是IEnumerable
,因此使用选择:
AttriuteTags.ExceptWith(attribute.AttributeTag.Select(item => item.value));
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value)
);
string[] AttributeTags =
txtAttributeTags.Text.Split
(
new string[] { "," },
StringSplitOptions.RemoveEmptyEntries
);
var newTags = AttributeTags.Except
(
attribute.AttributeTag.Select(item => item.value),
new CustomEqualityComparer<string>
(
(a, b) => 1, //your custom comparison here
str => str.GetHashCode()
)
);
这就增加了新标签,新标签
注意:如果需要进行特殊比较,则应使用:
遗憾的是,equalityComparer是一个实现IEqualityComparer的类的对象,这意味着不能在那里使用lambda。为此,您可以添加此类:
public class CustomEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _comparison;
private Func<T, int> _getHashCode;
public CustomEqualityComparer
(
Func<T, T, bool> comparison,
Func<T, int> getHashCode
)
{
if (ReferenceEquals(comparison, null))
{
throw new ArgumentNullException("comparison");
}
else if (ReferenceEquals(getHashCode, null))
{
throw new ArgumentNullException("getHashCode");
}
else
{
_comparison = comparison;
_getHashCode = getHashCode;
}
}
public bool Equals(T x, T y)
{
return _comparison.Invoke(x, y);
}
public int GetHashCode(T obj)
{
return _getHashCode.Invoke(obj);
}
}
比较解决方案
这些方法有什么不同
- 第一种方法需要更少的内存
- 第一个需要定义一个新方法
- 第一个不允许自定义
IEqualityComparer
- 第二个允许延迟执行
- 第二个使用(不需要)助手类
一个简单的例子,告诉你如何做你想做的事
var fromDB = new List<string>() { "a", "b", "c", "d", "e" };
var userInput = new List<string>() { "c", "d", "e", "f", "g" };
var result = fromDB.Join(userInput, x => x, y => y, (x, y) => x).Union(userInput);
var fromDB=newlist(){“a”、“b”、“c”、“d”、“e”};
var userInput=newlist(){“c”、“d”、“e”、“f”、“g”};
var result=fromDB.Join(userInput,x=>x,y=>y,(x,y)=>x).Union(userInput);
现在,您所要做的就是用结果替换数据库内容。使用Iesi.Collections可以非常优雅地解决此问题
它有几个实现,下面是一个:
这是我测试的代码。在实体框架中有很多保存的方法
注意:请确保在迭代集合时不修改/删除项
<asp:TextBox ID="txtAttributeTags" runat="server" />
<asp:Button runat="server" ID="SubmitButton" OnClick="SubmitButton_Click"
Text="Submit" />
public const int AttributeID = 1;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (var db = new AttributeEntities())
{
var tags = db.AttributeTags
.Where(a => a.attribute_id == AttributeID)
.Select(a => a.value);
txtAttributeTags.Text = string.Join(",", tags);
}
}
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
using (var db = new AttributeEntities())
{
string[] newTags = txtAttributeTags.Text.Split(new[] {","},
StringSplitOptions.RemoveEmptyEntries);
var oldTags = db.AttributeTags.Where(t => t.attribute_id == AttributeID);
foreach (var tag in oldTags.Where(o => !newTags.Contains(o.value)))
db.AttributeTags.DeleteObject(tag);
foreach (var tag in newTags.Where(n => !oldTags.Any(o => o.value == n)))
db.AttributeTags.AddObject(new AttributeTag
{
attribute_id = AttributeID, value = tag, timestamp = DateTime.Now
});
db.SaveChanges();
}
}
}
公共常数int AttributeID=1;
受保护的无效页面加载(对象发送方、事件参数e)
{
如果(!IsPostBack)
{
使用(var db=new attributentities())
{
var tags=db.AttributeTags
.Where(a=>a.attribute_id==AttributeID)
.选择(a=>a.value);
txtAttributeTags.Text=string.Join(“,”标记);
}
}
}
受保护的无效提交按钮单击(对象发送者,事件参数e)
{
使用(var db=new attributentities())
{
string[]newTags=txtAttributeTags.Text.Split(新[]{,“},
StringSplitOptions.RemoveEmptyEntries);
var oldTags=db.AttributeTags.Where(t=>t.attribute_id==AttributeID);
foreach(oldTags.Where(o=>!newTags.Contains(o.value))中的var标记)
db.AttributeTags.DeleteObject(标记);
foreach(newTags.Where(n=>!oldTags.Any(o=>o.value==n))中的var标记)
db.AttributeTags.AddObject(新的AttributeTag
{
attribute_id=AttributeID,value=tag,timestamp=DateTime.Now
});
db.SaveChanges();
}
}
}
你应该定义class属性、AttributeTags和你期望的结果,它很模糊,val
从哪里来?不,我不知道如何删除从用户输入中删除的标记。但是你的代码没有显示删除
?请阅读我的问题。。。移除部分是我不知道如何实现的。
var fromDB = new List<string>() { "a", "b", "c", "d", "e" };
var userInput = new List<string>() { "c", "d", "e", "f", "g" };
var result = fromDB.Join(userInput, x => x, y => y, (x, y) => x).Union(userInput);
ListSet set1 = new ListSet(new [] {"1","2","8"});
ListSet set2 = new ListSet(new [] {"8","16","32"});
var union = set1 | set2; // "1","2","8","16","32"
var intersect = set1 & set2; // "8"
var diff = set1 ^ set2; // "1","2","16","32"
var minus = set1 - set2; // "1","2"
<asp:TextBox ID="txtAttributeTags" runat="server" />
<asp:Button runat="server" ID="SubmitButton" OnClick="SubmitButton_Click"
Text="Submit" />
public const int AttributeID = 1;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (var db = new AttributeEntities())
{
var tags = db.AttributeTags
.Where(a => a.attribute_id == AttributeID)
.Select(a => a.value);
txtAttributeTags.Text = string.Join(",", tags);
}
}
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
using (var db = new AttributeEntities())
{
string[] newTags = txtAttributeTags.Text.Split(new[] {","},
StringSplitOptions.RemoveEmptyEntries);
var oldTags = db.AttributeTags.Where(t => t.attribute_id == AttributeID);
foreach (var tag in oldTags.Where(o => !newTags.Contains(o.value)))
db.AttributeTags.DeleteObject(tag);
foreach (var tag in newTags.Where(n => !oldTags.Any(o => o.value == n)))
db.AttributeTags.AddObject(new AttributeTag
{
attribute_id = AttributeID, value = tag, timestamp = DateTime.Now
});
db.SaveChanges();
}
}
}