我在C#Web API OData中使用以下代码并尝试对LanguageId
进行过滤,但是在应用过滤器时我收到以下给出的错误
模型
namespace ODataSample
{
public class Project
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public long CreatedBy { get; set; }
public long UpdatedBy { get; set; }
public decimal Cost { get; set; }
public long StatusId { get; set; }
[ForeignKey("StatusId")]
public virtual ProjectStatus Status { get; set; }
}
public class ProjectStatus
{
public ProjectStatus()
{
ProjectStatusTexts = new HashSet<ProjectStatusText>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long StatusId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<ProjectStatusText> ProjectStatusTexts { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
public class ProjectStatusText
{
public ProjectStatusText()
{
ProjectStatus = new HashSet<ProjectStatus>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public long StatusId { get; set; }
[ForeignKey("StatusId")]
public IEnumerable<ProjectStatus> ProjectStatus { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public long LanguageId { get; set; }
[ForeignKey("LanguageId")]
public virtual Language Language { get; set; }
public bool IsActive { get; set; }
}
public class Language
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long LanguageId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
}
public class User
{
public User()
{
this.Projects = new HashSet<Project>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
}
上述型号的服务
namespace ODataSample.Services
{
public class ProjectsService
{
public IQueryable<Project> GetProjects()
{
var ctx = new ProjectsContext();
return ctx.Projects;
}
}
}
DbContext
种子数据和DbInitializer
namespace ODataSample.Contexts
{
public class ProjectsContext : DbContext
{
public ProjectsContext() : base("ProjectsConnectionString") { Database.SetInitializer(new ProjectDBInitializer()); }
public ProjectsContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
Database.SetInitializer(new ProjectDBInitializer());
}
public DbSet<Project> Projects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ProjectStatus> ProjectStatuses { get; set; }
public DbSet<ProjectStatusText> ProjectStatusTexts { get; set; }
public DbSet<Language> Languages { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
public class ProjectDBInitializer : DropCreateDatabaseAlways<ProjectsContext>
{
public ProjectDBInitializer()
{
}
protected override void Seed(ProjectsContext context)
{
context.Languages.AddRange(new[]
{
new Language { Description = "Spanish", IsActive = true, LanguageId = 1, Name = "es" },
new Language { Description = "English", IsActive = true, LanguageId = 2, Name = "en" }
});
context.ProjectStatuses.AddRange(new[]
{
new ProjectStatus { StatusId=1, Name="Active", Description="Active", IsActive= true },
new ProjectStatus { StatusId=2, Name="Closed", Description="Closed", IsActive= true },
new ProjectStatus { StatusId=3, Name="InProgress", Description="In Progress", IsActive= true }
});
context.ProjectStatusTexts.AddRange(new[]
{
new ProjectStatusText {Id = 1, LanguageId=1, StatusId = 1,Name = Path.GetRandomFileName(),Description = Path.GetRandomFileName(),IsActive=true },
new ProjectStatusText {Id = 2, LanguageId=2, StatusId = 1,Name = "Active",Description = "Active",IsActive=true },
new ProjectStatusText {Id = 3, LanguageId=1, StatusId = 2,Name = Path.GetRandomFileName(),Description = Path.GetRandomFileName(),IsActive=true },
new ProjectStatusText {Id = 4, LanguageId=2, StatusId = 3,Name = "InProgress",Description = "InProgress",IsActive=true }
});
context.Projects.AddRange(new[]
{
new Project{ Cost = default(decimal), Id=1,Name="project 1",StatusId = 1, Description="project 1", CreatedOn = DateTime.Now, UpdatedOn = DateTime.Now, CreatedBy = 1, UpdatedBy =1},
new Project{ Cost = default(decimal), Id=2,Name="project 2",StatusId = 1, Description="project 2", CreatedOn = DateTime.Now, UpdatedOn = DateTime.Now, CreatedBy = 1, UpdatedBy =1},
new Project{ Cost = default(decimal), Id=3,Name="project 3",StatusId = 1, Description="project 3", CreatedOn = DateTime.Now, UpdatedOn = DateTime.Now, CreatedBy = 1, UpdatedBy =1 }
});
base.Seed(context);
}
}
}
以下是WebApiConfig
注册
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Project>("Projects");
modelBuilder.EntitySet<ProjectStatus>("ProjectStatusses");
modelBuilder.EntitySet<ProjectStatusText>("ProjectStatusTexts");
modelBuilder.EntitySet<Language>("Languages");
modelBuilder.EntitySet<User>("Users");
var edmModel = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("odata", "odata", edmModel);
问题:
我有Project
实体,其状态可用,如new,active,inprogress等。当我尝试对这些值进行本地化时,我发现拥有文本类/表的方法很容易。因此创建了ProjectStatusTexts
类/表。
当我尝试使用已翻译的值获取项目时,我使用浏览器中的以下OData查询,但它不会过滤记录,因为EF为任何子句返回ProjectStatusTexts
表中的所有记录。
我也尝试过StackOverflow中给出的以下方法,但无法修复。这个模型有什么问题,C#不理解或者OData查询URI有问题,请帮助。
查询URI: ?http://localhost:64046/odata/Projects $扩大=状态/ ProjectStatusTexts&安培; $滤波器=状态/ ProjectStatusTexts /任何(1:1 /语言/ LanguageId%20当量%202)
var projects = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("Projects");
var projectStatusTexts = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("ProjectStatusTexts");
var projectType = (EdmEntityType)edmModel.FindDeclaredType("ODataSample.Project");
var projectStatusTextsType = (EdmEntityType)edmModel.FindDeclaredType("ODataSample.ProjectStatusText");
var partsProperty = new EdmNavigationPropertyInfo();
partsProperty.TargetMultiplicity = EdmMultiplicity.Many;
partsProperty.Target = projectStatusTextsType;
partsProperty.ContainsTarget = false;
partsProperty.OnDelete = EdmOnDeleteAction.Cascade;
partsProperty.Name = "ProjectStatusTexts";
//projects.AddNavigationTarget(projectType.AddUnidirectionalNavigation(partsProperty), projectStatusTexts);
var navigationProperty = projectType.AddUnidirectionalNavigation(partsProperty);
projects.AddNavigationTarget(navigationProperty, projectStatusTexts);
var linkBuilder = edmModel.GetEntitySetLinkBuilder(projects);
linkBuilder.AddNavigationPropertyLinkBuilder(navigationProperty,
new NavigationLinkBuilder((context, property) =>
context.GenerateNavigationPropertyLink(property, false), true));
config.Routes.MapODataRoute("odata", "odata", edmModel);
答案 0 :(得分:0)
我认为您要实现的目标是获取所有项目,然后扩展到具有正确语言的ProjectStatusTexts
。如果是这种情况,那么过滤器是扩展的一部分,而不是Projects
自身查询的一部分,因此在扩展之后应该将其添加到括号中,如下所示:
http://localhost:64046/odata/Projects?$扩大=状态/ ProjectStatusTexts($滤波器=语言/ LanguageId%20当量%202)
答案 1 :(得分:0)
的答案为基础
在OP的架构中,Project
有一个Status
,而Status
有许多ProjectStatusText
在结果集中,我们只想包含与给定语言ID匹配的ProjectStatusText
条记录。
要实现这一点,我们需要扩展两次,在扩展到ProjectStatusTexts
中,我们还需要应用过滤器。
http://localhost:64046/odata/Projects?$expand=Status($expand=ProjectStatusTexts($filter=Language/LanguageId eq 2))
此查询将返回所有项目,但如果其语言ID与“英语”(2)相匹配,则仅包含ProjectStatusText
请注意,要访问多个级别的导航属性,我们必须使用嵌套的
$expand
运算符
OP尝试过滤的过程可以大致翻译为:
如果您还只想退回具有英文身份的项目,则可以将两种方法结合使用:
http://localhost:64046/odata/Projects?$expand=Status($expand=ProjectStatusTexts($filter=Language/LanguageId eq 2))&$filter=Status/ProjectStatusTexts/any(l:l/Language/LanguageId eq 2)
但是,这种类型的过滤器通常是多余的,特别是如果所有项目状态记录中都有每种受支持语言的条目。