2

我先使用代碼並試圖在List屬性上查看它是否包含過濾列表中的字符串。但是我遇到了問題。爲了簡單,假設如下。EF 4:引用非標量變量不受支持

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是一個字符串的選項。另外,我可能會過度並創建一個「顏色」實體,但這相當重。不幸的是,枚舉也不被支持。

回答

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; 
+0

您的示例將不起作用。您可以引用LOCAL標量變量的集合,但對於任何給定的實體,您不能引用非實體的集合屬性,即使這只是基元的集合。例如,如果你有p.FavorieColor(字符串),那麼你可以使用「filterBy.Contains(p.FavoriteColor)」,但是你不能迭代集合Property。 – 2011-02-18 19:03:32

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鑑於實施了其原來的目的,一個多選列表框。由於我未知的原因,如果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()); 

注意,該列表框當屬性是一個字符串列表時,不會發生錯誤,當它是一個實體列表時它不會喜歡它。