EF 4:引用不支持的非标量变量

时间:2011-02-17 20:35:20

标签: entity-framework-4 linq-to-entities code-first ef-code-first

我首先使用代码并尝试在List属性上执行简单查询,以查看它是否包含过滤列表中的字符串。但是我遇到了问题。为简单起见,假设如下。

public class Person
{
   public List<string> FavoriteColors { get; set; }
}

//Now some code. Create and add to DbContext
var person = new Person{ FavoriteColors = new List<string>{ "Green", "Blue"} };
dbContext.Persons.Add(person);
myDataBaseContext.SaveChanges();

//Build 
var filterBy = new List<string>{ "Purple", "Green" };
var matches = dbContext.Persons.AsQueryable();
matches = from p in matches
          from color in p.FavoriteColors 
          where filterBy.Contains(color)
          select p;

我正在考虑的选项是将其转换为json序列化字符串,因为如果FavoriteColors是一个字符串,我可以执行Contains调用。或者,我可以过火并创建一个“颜色”实体,但这相当重。不幸的是,枚举也不受支持。

2 个答案:

答案 0 :(得分:1)

我认为问题不是集合,而是对matches的引用。

var matches = dbContext.Persons.AsQueryable();
matches = from p in matches
          from color in p.FavoriteColors 
          where filterBy.Contains(color)
          select p;

如果您查看Known Issues and Considerations for EF4,这或多或少完全是上述情况。

  

引用非标量变量,   例如实体,在查询中不是   支持的。执行此类查询时   NotSupportedException异常是   抛出一条消息说明   “无法创建一个恒定值   输入EntityType。

另请注意,它特别指出支持引用标量变量的集合(这是EF 4 imo中的新功能)。

说过以下情况应该有效(现在不能试试):

matches = from p in dbContext.Persons
          from color in p.FavoriteColors 
          where filterBy.Contains(color)
          select p;

答案 1 :(得分:0)

我决定通过创建一个“StringEntity”类来克服这个限制进行实验,并使用隐式运算符对字符串进行很好的简单转换。请参阅下面的解决方案:

public class MyClass
{
    [Key, DatabaseGenerated(DatabaseGenerationOption.Identity)]
    public Guid Id { get; set; }
    public List<StringEntity> Animals { get; set; }
    public MyClass()
    {
        List<StringEntity> Animals = List<StringEntity>();
    }
}
public class StringEntity
{
    [Key, DatabaseGenerated(DatabaseGenerationOption.Identity)]
    public Guid Id { get; set; }
    public string Value { get; set; }

    public StringEntity(string value) { Value = value; }
    public static implicit operator string(StringEntity se) { return se.Value; }
    public static implicit operator StringEntity(string value) { return new StringEntity(value);  }
}
public class MyDbContext : DbContext
{           
    public DbSet<MyClass> MyClasses { get; set; }       

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyClass>()
            .HasMany(x => x.Animals)
            .WithMany()
            .Map(x =>
            {
                x.MapLeftKey(l => l.Id, "MyClassId");
                x.MapRightKey(r => r.Id, "StringEntityId");
            });
    }
}

......一切看起来都像是在完美地进行了一些测试(尽管很重),然后我实现了它的原始目的,一个MVC3视图中的Multiselect ListBox。由于我不知道的原因,如果为ListBox分配了与实体集合属性相同的名称,则不会加载任何选定的项目。

要证明以下内容不起作用: // Razor查看代码

string[] animalOptions = new string[] {"Dog", "Cat", "Goat"};
string[] animalSelections = new string[] {"Dog", "Cat"};
Html.ListBox("Animals", Multiselect(animalOptions, animalSelections));

为了解决这个限制,我需要做四件事:

//#1 Unpluralize the ListBox name so that is doesn't match the name Model.Animals
var animalOptions = new string[] {"Dog", "Cat", "Goat"};
@Html.ListBox("Animal", new MultiSelectList(animalOptions, Model.Animals.Select(x => x.Value)))

//#2 Use JQuery to replace the id and name attribute, so that binding can occur on the form post
<script type="text/javascript">
   jQuery(function ($) {
     $("select#Animal").attr("name", "Animals").attr("id", "Animals");
    });
</script>

//#3 Create a model binder class to handle List<StringEntity> objects 
public class StringEntityListBinder : IModelBinder
{
  public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
  {
     var stringArray = controllerContext.HttpContext.Request.Params.GetValues(bindingContext.ModelName);
     return stringArray.Select(x => new StringEntity(x)).ToList();
  }
}

//#4 Initialize the binder in your Global.asax setup.
ModelBinders.Binders.Add(typeof(List<StringEntity>), new StringEntityListBinder ());

请注意,当属性是字符串列表时,Listbox错误不会发生,当它是实体列表时,它只是不喜欢它。

相关问题