我首先使用代码并尝试在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调用。或者,我可以过火并创建一个“颜色”实体,但这相当重。不幸的是,枚举也不受支持。
答案 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错误不会发生,当它是实体列表时,它只是不喜欢它。