Entity Framework 5 Won't Fetch Relationships With Include() - c#

I am quite certain that questions like this have been answered a number of times before, but I can't get any of the suggestions to work.
I am building a MVC 4 application with Entity Framework 5, where the entities were generated from existing tables. I have entity classes that look like this:
namespace RebuildingModel
{
using System;
using System.Collections.Generic;
public partial class StandardCodeTable
{
public StandardCodeTable()
{
this.StandardCodeTableTexts = new HashSet<StandardCodeTableText>();
}
public int TableCode { get; set; }
public string RefTableName { get; set; }
public virtual ICollection<StandardCodeTableText> StandardCodeTableTexts { get; set; }
}
}
namespace RebuildingModel
{
using System;
using System.Collections.Generic;
public partial class StandardCodeTableText
{
public int TableCode { get; set; }
public string LanguageCode { get; set; }
public string TextVal { get; set; }
public virtual StandardCodeTable StandardCodeTable { get; set; }
}
}
namespace RebuildingSite.Models
{
public class CodeTableJoined
{
public int TableCode { get; set; }
public string ReferenceTableName { get; set; }
public string LanguageCode { get; set; }
public string TextValue { get; set; }
}
}
I have a DAO that looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RebuildingModel.Dao
{
public class CodeTableDao
{
public CodeTableDao() { }
public ISet<StandardCodeTableText> GetCode(string refTableName)
{
HashSet<StandardCodeTableText> codes = new HashSet<StandardCodeTableText>();
using (var db = new RebuildingTogetherEntities())
{
db.StandardCodeTableTexts.Include("StandardCodeTables");
var query = from c in db.StandardCodeTableTexts
where c.StandardCodeTable.RefTableName == refTableName
orderby c.TableCode
select c;
foreach (var item in query)
{
codes.Add(item);
}
}
return codes;
}
}
I have a controller that looks like this:
namespace RebuildingSite.Controllers
{
public class CodeTableController : Controller
{
public ActionResult Index(string refTableName)
{
CodeTableDao dao = new CodeTableDao();
ICollection<StandardCodeTableText> codes = dao.GetCode(refTableName);
HashSet<CodeTableJoined> joins = new HashSet<CodeTableJoined>();
foreach (var code in codes)
{
CodeTableJoined join = new CodeTableJoined();
join.TableCode = code.TableCode;
join.LanguageCode = code.LanguageCode;
join.TextValue = code.TextVal;
join.ReferenceTableName = code.StandardCodeTable.RefTableName;
joins.Add(join);
}
ISet<string> refTableNames = dao.GetReferenceTables();
ViewBag.RefTableNames = refTableNames;
return View(joins);
}
}
}
When I run the view attached to the controller, an ObjectDisposedException is thrown at this line, where the relationship is used:
join.ReferenceTableName = code.StandardCodeTable.RefTableName;
This has to be something simple. What am I doing wrong? I have tried adding that Include() call in from the context in many different places, even multiple times.
I've also tried adding an explicit join in the Linq query. I can't get EF to fetch that relationship.

Copying my comment to an answer - Put the include be in the actual query
var query = from c in
db.StandardCodeTableTexts.include("StandardCodeTables"). where
c.StandardCodeTable.RefTableName == refTableName orderby c.TableCode
select c;

Related

C#: Dapper with JsonConvert.SerializeObject() not working properly

I'm new to Newtonsoft.Json and Dapper.
I am executing an SQL query, and using the query's result I'm converting it to a JSON string to try to make it look like this:
{ "Orders" : [{"OrderID":10248, "Quantity":12}, {"OrderID":10343, "Quantity":4}, ...etc...]}
However when I run my C# code, my output looks completely different along with some unexpected additions:
[
{
"JSON_F52E2B61-18A1-11d1-B105-00805F49916B": "{\"Orders\":[{\"OrderID\":10248,\"Quantity\":12},{\"OrderID\":10248,\"Quantity\":10}{\"OrderID\":10271,\"Quantity\":24},{\"OrderID\":10272,\"Quantity\":6},{\"OrderID\":1027"
},
{
"JSON_F52E2B61-18A1-11d1-B105-00805F49916B": "2,\"Quantity\":40},{\"OrderID\":10272,\"Quantity\":24}, ...etc... ]
As you can see I do not understand why it is adding the additional "JSON_F52E2B61-18A1-11d1-B105-00805F49916B". How do I remove these? How do I change my code to make it look like my desired output json string?
This is my code. I also made a fiddle with the incorrect output I'm getting https://dotnetfiddle.net/uWV6vs :
// Dapper Plus
// Doc: https://dapper-tutorial.net/query
// #nuget: Dapper -Version 1.60.6
using Newtonsoft.Json;
using Dapper;
using System;
using System.Data.SqlClient;
public class Program
{
public class OrderDetail
{
public int OrderDetailID { get; set; }
public int OrderID { get; set; }
public int ProductID { get; set; }
public int Quantity { get; set; }
}
public static void Main()
{
string sql = "SELECT OrderID, Quantity FROM OrderDetails FOR JSON PATH, root ('Orders'), INCLUDE_NULL_VALUES";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
dynamic orderDetail = connection.Query(sql);
//edit: the answer is to use connection.Query<string>, orderDetail[0]
orderDetail = JsonConvert.SerializeObject(orderDetail,Formatting.Indented);
Console.WriteLine(orderDetail);
}
}
}
I believe you don't need to request JSON from SQL, Dapper will parse results to the objects automatically
Removing "FOR JSON PATH, root ('Orders'), INCLUDE_NULL_VALUES" should help
string sql = "SELECT OrderID, Quantity FROM OrderDetails";
UPDATE:
sorry, keep updating the answer. This one gives you objects with the right structure and no extra backslashes
using Newtonsoft.Json;
using Dapper;
using System;
using System.Data.SqlClient;
using System.Collections.Generic;
public class Program
{
public class OrderDetail
{
public int OrderDetailID { get; set; }
public int OrderID { get; set; }
public int ProductID { get; set; }
public int Quantity { get; set; }
}
public class Result
{
public IEnumerable<OrderDetail> Orders { get; set; }
}
public static void Main()
{
string sql = "SELECT OrderID, Quantity FROM OrderDetails";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
var orderDetail = connection.Query<OrderDetail>(sql);
var str = JsonConvert.SerializeObject(new Result { Orders = orderDetail },Formatting.Indented);
Console.WriteLine(str);
}
}
}

Application service URL mapping on ABP

I'm new to ABP, and I did this oficial tutorial succesfully.
The thing is that then I added another class (Planta) and followed the tutorial again (without deleting The Book class), but even when I can create the table and feed data on it (verified), the application fails to load the table, and when I checked the swagger, I found this...
I was expecting it to be Planta instead of BookAppServicePlanta, and I can't find where did I messed things up.
Things I've tryed to solve this
I have readed the most that I have been able to about ABP.
I've contrasted every Planta file whith it's Book counterpart.
I've dropped the database many times.
Here is what I did (details below):
I created the class planta on Acme.BookStore.Domain/Planta/Planta.cs:
Added the entity to Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs
Mapped the entity to the table on Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContextModelCreatingExtensions.cs
Dropped the database, and deleted previous migrations
Created a Data Seeder Acme.BookStore.Domain/BookStoreDataSeederContributor_Plant.cs
Added a new migration, and ran Acme.BookStore.DbMigrator
Created Acme.BookStore.Application.Contracts/PlantDto.cs
Added it to the Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
created Acme.BookStore.Application.Contracts/CreateUpdatePlantDto.cs (and added it too to the automapper as shown on 8) )
created the interface Acme.BookStore.Application.Contracts/IBookAppServicePlanta.cs
Implemented it on Acme.BookStore.Application/BookAppServicePlanta.cs
Ran the application
Extra Info:
I created the pages for Planta and its forms (tutorial part 2 and 3), but even I've double checked those files, I dont belive the problem is on those files, since swagger problem.
I created the class planta on Acme.BookStore.Domain/Planta/Planta.cs:
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.Plantas
{
public class Planta : AuditedAggregateRoot<Guid>
{
public string Nombre { get; set; }
public string Descripcion { get; set; }
public string Dirección { get; set; }
public string Lat { get; set; }
public string Long { get; set; }
public string Extra1 { get; set; }
public string Extra2 { get; set; }
public string Extra3 { get; set; }
}
}
Added the entity to Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs
using Microsoft.EntityFrameworkCore;
using Acme.BookStore.Users;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.Identity;
using Volo.Abp.Users.EntityFrameworkCore;
using Acme.BookStore.Books;
using Acme.BookStore.Plantas;
namespace Acme.BookStore.EntityFrameworkCore
{
/* This is your actual DbContext used on runtime.
* It includes only your entities.
* It does not include entities of the used modules, because each module has already
* its own DbContext class. If you want to share some database tables with the used modules,
* just create a structure like done for AppUser.
*
* Don't use this DbContext for database migrations since it does not contain tables of the
* used modules (as explained above). See BookStoreMigrationsDbContext for migrations.
*/
[ConnectionStringName("Default")]
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<AppUser> Users { get; set; }
public DbSet<Book> Books { get; set; }
public DbSet<Planta> Plantas { get; set; }
/* Add DbSet properties for your Aggregate Roots / Entities here.
* Also map them inside BookStoreDbContextModelCreatingExtensions.ConfigureBookStore
*/
public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Configure the shared tables (with included modules) here */
builder.Entity<AppUser>(b =>
{
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
b.ConfigureByConvention();
b.ConfigureAbpUser();
/* Configure mappings for your additional properties
* Also see the BookStoreEfCoreEntityExtensionMappings class
*/
});
/* Configure your own tables/entities inside the ConfigureBookStore method */
builder.ConfigureBookStore();
}
}
}
Mapped the entity to the table on Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContextModelCreatingExtensions.cs
using Acme.BookStore.Books;
using Acme.BookStore.Plantas;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace Acme.BookStore.EntityFrameworkCore
{
public static class BookStoreDbContextModelCreatingExtensions
{
public static void ConfigureBookStore(this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
/* Configure your own tables/entities inside here */
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books",
BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
builder.Entity<Planta>(p =>
{
p.ToTable(BookStoreConsts.DbTablePrefix + "Plantas",
BookStoreConsts.DbSchema);
p.ConfigureByConvention(); //auto configure for the base class props
p.Property(y => y.Nombre).IsRequired().HasMaxLength(128);
});
}
}
}
Dropped the database, and deleted previous migrations
Created a Data Seeder Acme.BookStore.Domain/BookStoreDataSeederContributor_Plant.cs
using System;
using System.Threading.Tasks;
using Acme.BookStore.Plantas;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookStoreDataSeederContributor_Plant
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Planta, Guid> _plantaRepository;
public BookStoreDataSeederContributor_Plant(IRepository<Planta, Guid> plantaRepository)
{
_plantaRepository = plantaRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _plantaRepository.GetCountAsync() > 0)
{
return;
}
await _plantaRepository.InsertAsync(
new Planta
{
Nombre = "Armijo Guajardo",
Descripcion = "excel god",
Dirección = "las lilas 123",
Lat = "564.765.98",
Long = "100.102.04",
Extra1 = "bla",
Extra2 = "bla bla",
Extra3 = "bla bla bla"
},
autoSave: true
);
}
}
}
Added a new migration, and ran Acme.BookStore.DbMigrator
Created Acme.BookStore.Application.Contracts/PlantDto.cs
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Plantas
{
public class PlantDto : AuditedEntityDto<Guid>
{
public string Nombre { get; set; }
public string Descripcion { get; set; }
public string Dirección { get; set; }
public string Lat { get; set; }
public string Long { get; set; }
public string Extra1 { get; set; }
public string Extra2 { get; set; }
public string Extra3 { get; set; }
}
}
Added it to the Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
using Acme.BookStore.Books;
using Acme.BookStore.Plantas;
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
CreateMap<CreateUpdateBookDto, Book>();
CreateMap<Planta, PlantDto>();
CreateMap<CreateUpdatePlantDto, Planta>();
}
}
}
created Acme.BookStore.Application.Contracts/CreateUpdatePlantDto.cs (and added it too to the automapper as shown on 8) )
using System;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore.Plantas
{
public class CreateUpdatePlantDto
{
[Required]
[StringLength(128)]
public string Nombre { get; set; }
[Required]
[StringLength(128)]
public string Descripcion { get; set; }
[Required]
[StringLength(128)]
public string Dirección { get; set; }
[Required]
[StringLength(128)]
public string Lat { get; set; }
[Required]
[StringLength(128)]
public string Long { get; set; }
[Required]
[StringLength(128)]
public string Extra1 { get; set; }
[Required]
[StringLength(128)]
public string Extra2 { get; set; }
[Required]
[StringLength(128)]
public string Extra3 { get; set; }
}
}
created the interface Acme.BookStore.Application.Contracts/IBookAppServicePlanta.cs
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Plantas
{
public interface IBookAppServicePlanta :
ICrudAppService< //Defines CRUD methods
PlantDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdatePlantDto> //Used to create/update a book
{
}
}
Implemented it on Acme.BookStore.Application/BookAppServicePlanta.cs
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Plantas
{
public class BookAppServicePlanta :
CrudAppService<
Planta, //The Book entity
PlantDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdatePlantDto>, //Used to create/update a book
IBookAppServicePlanta //implement the IBookAppService
{
public BookAppServicePlanta(IRepository<Planta, Guid> repository)
: base(repository)
{
}
}
}
Ran the application
[EDIT]
Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs looks like this
using Acme.BookStore.Books;
using Acme.BookStore.Plantas;
using AutoMapper;
namespace Acme.BookStore.Web
{
public class BookStoreWebAutoMapperProfile : Profile
{
public BookStoreWebAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
CreateMap<PlantDto, CreateUpdatePlantDto>();
}
}
}
[EDIT]
I created a teting file Acme.BookStore.Application.Tests/BookAppServicePlanta_test.cs, and they all succeded.
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Plantas
{
public class BookAppService_Tests : BookStoreApplicationTestBase
{
private readonly IBookAppServicePlanta _plantaAppService;
public BookAppService_Tests()
{
_plantaAppService = GetRequiredService<IBookAppServicePlanta>();
}
[Fact]
public async Task Should_Get_List_Of_Books()
{
//Act
var result = await _plantaAppService.GetListAsync(
new PagedAndSortedResultRequestDto()
);
//Assert
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Nombre == "Armijo Guajardo");
}
[Fact]
public async Task Should_Create_A_Valid_Planta()
{
//Act
var result = await _plantaAppService.CreateAsync(
new CreateUpdatePlantDto
{
Nombre = "Pedro Cano",
Descripcion = "Cirujano",
Dirección = "Pedro de Valdivia",
Lat = "123213213",
Long = "456456456",
Extra1 = "emmmm",
Extra2 = "no se",
Extra3 = "que poner"
}
);
//Assert
result.Id.ShouldNotBe(Guid.Empty);
result.Nombre.ShouldBe("Pedro Cano");
}
[Fact]
public async Task Should_Not_Create_A_Planta_Without_Name()
{
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
{
await _plantaAppService.CreateAsync(
new CreateUpdatePlantDto
{
Descripcion = "Cirujano",
Dirección = "Pedro de Valdivia",
Lat = "123213213",
Long = "456456456",
Extra1 = "emmmm",
Extra2 = "no se",
Extra3 = "que poner"
}
);
});
exception.ValidationErrors
.ShouldContain(err => err.MemberNames.Any(mem => mem == "Nombre"));
}
}
}
I am not familiar with ABP, but from a quick view to the documentation, it appears that you are not following the naming convention.
The application services should follow this naming convention: EntityAppService
But it appears you copied/pasted the previous class BookAppService and just added Planta to the end. It should be PlantaAppService instead.
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Plantas
{
public interface IPlantaAppService :
ICrudAppService< //Defines CRUD methods
PlantDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdatePlantDto> //Used to create/update a book
{
}
}
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Plantas
{
public class PlantaAppService:
CrudAppService<
Planta, //The Book entity
PlantDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdatePlantDto>, //Used to create/update a book
IPlantaAppService //implement the IPlantaAppService
{
public BookAppServicePlanta(IRepository<Planta, Guid> repository)
: base(repository)
{
}
}
}

Raw queries with overridden column names

I'm trying to retrieve some entities using Entity Framework by querying an XML column. Entity Framework doesn't support this so I had to use raw SQL.
var people = context.People.SqlQuery("SELECT * FROM [People] WHERE [DataXML].value('Properties/Age', 'int') = 21").AsQueryable().AsNoTracking();
My person class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[Column("YearsSinceBirth")]
public int Age { get; set; }
[Column(TypeName = "xml")]
public string DataXML { get; set; }
}
This should work, however, it falls over when trying to map it back to an object. Specifically, it's falling over on the Age property, which has it's column name overridden to "YearsSinceBirth".
'The data reader is incompatible with the specified
'MyProject.CodeBase.DataModel.DbEntities.Person'. A member of the
type, 'Age', does not have a corresponding column in the data reader
with the same name.'
I'm guessing that Entity Framework doesn't map database column names to object property names and therefore is expecting the column to be named 'Age' rather than 'YearsSinceBirth'.
I don't want to have to list each column and their mapping in the SQL query (like SELECT YearsSinceBirth As Age) as the actual project I'm working on which has this column has a lot more columns and that would mean this query would break every time the schema changed (kinda defeating the purpose of Entity Framework).
If this is EF Core, your problem is not that SqlQuery() doesn't support mapping column names (it does). Rather your problem is that your table doesn't contain a column called YearsSinceBirth, and you are returning 'select *'.
If you have a column called YearsSinceBirth, this works fine. Although you will be retrieving the value in the YearsSinceBirth column, not the value in the XML document. EG
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
//using Microsoft.Samples.EFLogging;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Data.SqlClient;
namespace EFCore2Test
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[Column("YearsSinceBirth")]
public int Age { get; set; }
[Column(TypeName = "xml")]
public string DataXML { get; set; }
}
public class Location
{
public string LocationId { get; set; }
}
public class Db : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Location> Locations { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(local);Database=EFCoreTest;Trusted_Connection=True;MultipleActiveResultSets=true");
base.OnConfiguring(optionsBuilder);
}
}
class Program
{
static void Main(string[] args)
{
using (var db = new Db())
{
db.Database.EnsureDeleted();
//db.ConfigureLogging(s => Console.WriteLine(s));
db.Database.EnsureCreated();
var p = new Person()
{
Name = "joe",
Age = 2,
DataXML = "<Properties><Age>21</Age></Properties>"
};
db.People.Add(p);
db.SaveChanges();
}
using (var db = new Db())
{
var people = db.People.FromSql("SELECT * FROM [People] WHERE [DataXML].value('(/Properties/Age)[1]', 'int') = 21").AsNoTracking().ToList() ;
Console.WriteLine(people.First().Age);
Console.ReadLine();
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
You can use a pattern similar to this to project entity attributes from an XML or JSON column:
public class Person
{
private XDocument xml;
public int Id { get; set; }
public string Name { get; set; }
[NotMapped]
public int Age
{
get
{
return int.Parse(xml.Element("Properties").Element("Age").Value);
}
set
{
xml.Element("Properties").Element("Age").Value = value.ToString();
}
}
[Column(TypeName = "xml")]
public string DataXML
{
get
{
return xml.ToString();
}
set
{
xml = XDocument.Parse(value);
}
}
}
You can dynamically create select query with aliases, if they needed, with the help of reflection and ColumnAttribute checking:
public string SelectQuery<T>() where T : class
{
var selectQuery = new List<string>();
foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var attr = prop.GetAttribute<ColumnAttribute>();
selectQuery.Add(attr != null ? $"{attr.Name} as {prop.Name}" : prop.Name);
}
return string.Join(", ", selectQuery);
}
Usage:
var people = context.People.SqlQuery($"SELECT {SelectQuery<Person>()} FROM [People] WHERE [DataXML].value('Properties/Age', 'int') = 21")
.AsQueryable().AsNoTracking();

Entity Framework 5 - LINQ syntax error

I have the following code where I am creating a IList that I need to filter by the data in another list called List. The locations list represents the locations a user is allowed to view based on their permissions. I am new to LINQ and am confused with error I get (C# Unknown method "Where(?)" of "System.Ling.IQueryable". I have tried various syntax arrangement using either Contains() and Any() or both to no avail. I feel like it's something very basic that I don't understand about doing this. Here is the code:
----- users locations
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Decking.Models
{
public class locations
{
[Key]
public string org_id { get; set; }
}
}
///////// here is the view model
using System.ComponentModel.DataAnnotations;
using System;
namespace Decking.Models
{
public class InventoryViewModel
{
[Key]
public int id { get; set; }
public DateTime metric_dt { get; set; }
public int? item_id { get; set; }
public int? loc_type_id { get; set; }
public string trlr_nbr { get; set; }
public string user_id { get; set; }
public string org_id { get; set; }
public Double numerator { get; set; }
//these are the child entities
[UIHint("ClientItem")]
public ItemViewModel Items
{
get;
set;
}
[UIHint("ClientLocTypes")]
public LocTypesViewModel LocTypes
{
get;
set;
}
[UIHint("ClientOrgsByUser")]
public OrgsByUserViewModel OrgsByUser
{
get;
set;
}
}
}
///////// code to populate the view model
public IList<InventoryViewModel> GetAll(List<locations> locs)
{
IList<InventoryViewModel> result = new List<InventoryViewModel>();
result = entities.inventory.Select(inventory => new
InventoryViewModel
{
id = inventory.id,
metric_dt = inventory.metric_dt,
item_id = inventory.item_id,
loc_type_id = inventory.loc_type_id,
trlr_nbr = inventory.trlr_nbr,
org_id = inventory.org_id,
numerator = inventory.numerator,
user_id = inventory.user_id,
Items = new ItemViewModel()
{
item_id = inventory.items.item_id,
item_desc = inventory.items.item_desc,
},
LocTypes = new LocTypesViewModel()
{
loc_type_id = inventory.loc_types.loc_type_id,
loc_desc = inventory.loc_types.loc_desc,
},
OrgsByUser = new OrgsByUserViewModel()
{
user_id = inventory.user_id,
//mgr_emp_nbr = inventory.mgr,
org_id = inventory.org_id,
},
}).Where(e => e.metric_dt == DateTime.Today && e.org_id
==locs.Any(o=>o.org_id)) // this doesn't work
//}).Where(e => e.metric_dt == DateTime.Today && e.org_id == "SGF") //
this works
.ToList();
return result;
}
Any help you can provide would be greatly appreciated! Thank so much!
The problem is in e.org_id == locs.Any(o=>o.org_id). As I can see in your working example, your org_id is a string.
I guess what you are trying to do is .Where(e => e.metric_dt == DateTime.Today && locs.Any(o=>o.org_id == e.org_id))

Setting data in multiple nested lists ASP.NET MVC C#

I'm an intern with very basic knowledge of ASP and C#.
I'm trying to display a list of projects > maps > thememaps in an application I'm working on in ASP.NET MVC. In my third foreach I get an error saying: "Does not contain a definition for "ThemeMaps" and no extension method "ThemeMaps" accepting a first argument of type could be found".
I'm confused as to why vmProject.Maps does not contain the property ThemeMaps. I instantiated that list just like maps. What am I doing wrong?
LayersController.cs
// Create viewmodel object
var viewModel = new AddLayerToThemeMapViewModel();
// Create Project list
viewModel.Projects = new List<AddProject>();
// Loop over all maps
List<Project> projects = this.applicationDb.Projects.OrderBy(e => e.Title).ToList();
foreach (var project in projects)
{
// Create map
var vmProject = new AddProject()
{
ProjectId = project.ProjectID,
ProjectTitle = project.Title,
Maps = new List<AddLayerMap>(),
};
foreach (var map in project.Maps.OrderBy(e => e.Title))
{
// Create map
vmProject.Maps.Add(new AddLayerMap()
{
MapId = map.MapId,
MapTitle = map.Title,
ThemeMaps = new List<AddLayerMapThemeMap>(),
});
// Loop over all thememaps in map
foreach (var thememap in map.ThemeMaps.OrderBy(e => e.Order))
{
vmProject.Maps.ThemeMaps.Add(new AddLayerMapThemeMap()
{
ThemeMapId = thememap.ThemeMapId,
ThemeMapTitle = thememap.Title,
});
}
}
// Add map to list
viewModel.Projects.Add(vmProject);
}
My viewmodel class
using Mapgear.MapViewer.Entities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Mapgear.MapViewer.ViewModels
{
public class AddLayerToThemeMapViewModel
{
public Guid LayerId { get; set; }
public List<AddProject> Projects { get; set; }
}
public class AddProject
{
public Guid ProjectId { get; set; }
public string ProjectTitle { get; set; }
public List<AddLayerMap> Maps { get; set; }
}
public class AddLayerMap
{
public Guid MapId { get; set; }
public string MapTitle { get; set; }
public List<AddLayerMapThemeMap> ThemeMaps { get; set; }
}
public class AddLayerMapThemeMap
{
public Guid ThemeMapId { get; set; }
public string ThemeMapTitle { get; set; }
}
}
I made a scetch before I started on paper, which looks like the following:
LayerId
List project
ProjectId
ProjectTitle
List Map
MapId
MapTitle
List ThemeMap
ThemeMapId
ThemeMapTitle
I know my class names are a bit out of wack, however I din't write them myself. Gonna optimize them after.
PS: This is my first question on StackOverflow!
I modified the code in the second for-each loop a bit. I added a variable for the newly created map and add the thememaps to this created map. Check if it's correct.
var newMap = new AddLayerMap()
{
MapId = map.MapId,
MapTitle = map.Title,
ThemeMaps = new List<AddLayerMapThemeMap>(),
};
// Create map
vmProject.Maps.Add(newMap);
// Loop over all thememaps in map
foreach (var thememap in map.ThemeMaps.OrderBy(e => e.Order))
{
newMap.ThemeMaps.Add(new AddLayerMapThemeMap()
{
ThemeMapId = thememap.ThemeMapId,
ThemeMapTitle = thememap.Title,
});
}

Categories