Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.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
C# 匹配两个项目列表的LINQ查询_C#_Asp.net_Linq_Entity Framework - Fatal编程技术网

C# 匹配两个项目列表的LINQ查询

C# 匹配两个项目列表的LINQ查询,c#,asp.net,linq,entity-framework,C#,Asp.net,Linq,Entity Framework,我的问题是,我有一个来自实体框架的属性作为“attribute”。 所以我检索这个对象,它有一个属性标签列表,它们可以通过attribute.AttributeTags访问。现在我有了一个asp:TextBox,用户可以在其中编辑、删除和添加新标记(逗号分隔)。(在页面加载时,我正在将属性标记添加到此文本框) 在页面上回发后,我返回用户输入并将其拆分为字符串数组,并将其存储在名为AttributeTags的变量中 现在,我想添加未包含在EF原始属性列表中的新标记,并想删除属性中包含但未在用户输入

我的问题是,我有一个来自实体框架的属性作为“attribute”。 所以我检索这个对象,它有一个属性标签列表,它们可以通过
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();
          }
        }
      }