EF Core LINQ查询的枚举列表

huangapple go评论85阅读模式
英文:

List of enums EF Core LINQ query

问题

public enum GeneticModificationTypes
{
SomeType = 1,
AnotherType = 2,
ThirdType = 3
}

public class GeneticModification: FullAuditedEntity
{
public ICollection Types { get; set; }
}

modelBuilder.Entity()
.Property(e => e.Types)
.HasConversion(
v => string.Join(',', v),
v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List())
.Metadata.SetValueComparer(valueComparer);

var valueComparer = new ValueComparer<ICollection>(
(c1, c2) => c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => (ICollection)c.ToHashSet());

When I try to:

_context.GeneticModification.Where(r => r.GeneticModification.Any(b => listOfTypes.Contains(b)))

or

_context.GeneticModification.Where(r => r.GeneticModification.Contains(listOfTypes.Contains(b))

edit

it throws:

Message: 

System.InvalidOperationException : The LINQ expression 'DbSet()
.Where(m => m.OrganizationId == __organizationId_0)
.OrderBy(m => m.CreationTime)
.Skip(__p_1)
.Take(__p_2)
.Where(m => m.GeneticModificationTypes
.Contains(__filters_GeneticModificationTypes_Value_3))' could not be translated. Additional information: Translation of method 'System.Linq.Enumerable.Contains' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

What this model does is creating a Varchar column on the Table GeneticModification where the ICollection on my model gets translated to "Type1, Type2".

The table is the follow:
GeneticModification
Id | Types
Guid | SomeType, AnotherType

英文:
public enum GeneticModificationTypes
{
    SomeType = 1,
    AnotherType = 2,
    ThirdType = 3
}

public class GeneticModification: FullAuditedEntity&lt;Guid&gt;
{
   public ICollection&lt;GeneticModificationTypes&gt; Types { get; set; } 
}

modelBuilder.Entity&lt;GeneticModification&gt;()
        .Property(e =&gt; e.Types)
        .HasConversion(
            v =&gt; string.Join(&#39;,&#39;, v),
            v =&gt; v.Split(&#39;,&#39;, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List&lt;GeneticModiciation&gt;())
        .Metadata.SetValueComparer(valueComparer);

var valueComparer = new ValueComparer&lt;ICollection&lt;string&gt;&gt;(
                    (c1, c2) =&gt; c1.SequenceEqual(c2),
                    c =&gt; c.Aggregate(0, (a, v) =&gt; HashCode.Combine(a, v.GetHashCode())),
                    c =&gt; (ICollection&lt;string&gt;)c.ToHashSet());

When I try to:

_context.GeneticModification.Where(r =&gt; r.GeneticModification.Any(b =&gt; listOfTypes.Contains(b))) 

or

_context.GeneticModification.Where(r =&gt; r.GeneticModification.Contains(listOfTypes.Contains(b))

edit

it throws:

Message: 

System.InvalidOperationException : The LINQ expression &#39;DbSet&lt;GeneticModification&gt;()
    .Where(m =&gt; m.OrganizationId == __organizationId_0)
    .OrderBy(m =&gt; m.CreationTime)
    .Skip(__p_1)
    .Take(__p_2)
    .Where(m =&gt; m.GeneticModificationTypes
        .Contains(__filters_GeneticModificationTypes_Value_3))&#39; could not be translated. Additional information: Translation of method &#39;System.Linq.Enumerable.Contains&#39; failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to &#39;AsEnumerable&#39;, &#39;AsAsyncEnumerable&#39;, &#39;ToList&#39;, or &#39;ToListAsync&#39;. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

What this model does is creating a Varchar column on the Table GeneticModification where the ICollection on my model gets translated to "Type1, Type2".

The table is the follow:
GeneticModification
Id | Types
Guid | SomeType, AnotherType

答案1

得分: 1

看起来你的数据库中有一个列,其中包含多个数字值被连接成一个字符串。如果你想要在该列中按独立值进行过滤或排序,这是非常糟糕的。即使在纯SQL中,这也会变得混乱和低效,而LINQ没有任何魔法来生成那种SQL。

理想情况下,我会使用一个相关的表来代替在该列中使用连接的值。如果你不能改变数据库结构,那么C# 有更好的方法将这些字符串转换为数组,并可以在那里进行过滤和排序,但你需要加载更多的数据到内存中,否则你无法做到这一点。

要实现这一点,你需要构建你的基本查询,然后插入 AsEnumerable() 以从SQL上下文切换到内存上下文,然后拆分字符串并从那里进行任何你需要的过滤。

英文:

It looks like your database has a column with multiple numeric values concatenated into one string. This is VERY VERY bad if you want to filter or sort base don individual value within that column. It's messy and inefficient even in straight SQL, and Linq doesn't have any magic to generate that SQL.

Ideally I would use a related table instead of concatenated values in that column. If you can't change the database structure, then C# Has better ways of turning those strings into arrays, and can filter and sort from there, but you'll have to load mode data into memory that you otherwise would.

To do that, you'd build your base query, then insert AsEnumerable() to change from a SQL context to an in-memory context, then split the strings and do whatever filtering you need to from there.

huangapple
  • 本文由 发表于 2023年2月23日 22:28:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546175.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定