I have 2 related entities in EF Core (database first design from an existing database) and having trouble loading one-many relationship - it's a webapi ASP.NET core 1.0 application
Brand Entity
[Table("tblBranding")]
public class Brand {
[Key]
[Column("brandingId")]
public int BrandId { get; set; }
[Column("BrandingActive")]
public bool Active { get; set; }
[JsonIgnore]
[Column("DeadBrand")]
public bool DeadBrand { get; set; }
[Column("BrandingSiteTitle")]
public string Name { get; set; }
//navigation properties
public virtual ICollection<Event> Events { get; set; }
}
Event entity:
[Table("tblEvents")]
public class Event
{
public int EventId { get; set; }
[Column("eventActive")]
public bool Active { get; set; }
[Column("eventName")]
public string Name { get; set; }
public DateTime EventCloseDate {get;set;}
public int PaxAllocationLimit { get; set; }
//navigation properties
[Column("BrandingId")]
public int BrandId { get; set; }
public virtual Brand Brand { get; set; }
public virtual ICollection<Session> Sessions { get; set; }
}
code from for FLUID API in OnModelCreating in DbContext:
modelBuilder.Entity<Event>()
.HasOne(e => e.Brand)
.WithMany(b => b.Events).HasForeignKey(e=>e.BrandId);
public virtual DbSet<Brand> Brands { get; set; }
public virtual DbSet<Event> Events { get; set; }
code from BrandsController:
[HttpGet]
public IActionResult Get() {
//var brands = from b in _context.Brands
// where b.Active == true
// orderby b.BrandName
// select b;
var brands = _context.Brands.Include(e => e.Events).Where(b => b.Active == true).OrderBy(b => b.Name);
return new ObjectResult(brands);
}
code from EventsController
// GET: api/values
[HttpGet("{id:int?}")]
public IActionResult Get(int? id) {
var events = from e in _context.Events
where e.Active == true
orderby e.Name
select e;
if (!events.Any()) {
return HttpNotFound();
}
if (id != null) {
events = events.Where(e => e.EventId == id).OrderBy(e => 0);
if (events.Count() == 0) { return HttpNotFound(); }
return new ObjectResult(events);
}
else {
return new ObjectResult(events);
}
}
When I try to load brands through the API, I get an exception:
Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory: Information: Executed DbCommand (80ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [t].[EventId], [t].[EventCloseDate], [t].[eventActive], [t].[BrandingId], [t].[EventId1], [t].[eventName], [t].[PaxAllocationLimit]
FROM [tblEvents] AS [t]
INNER JOIN (
SELECT DISTINCT [e].[BrandingSiteTitle], [e].[brandingId]
FROM [tblBranding] AS [e]
WHERE [e].[BrandingActive] = 1
) AS [e] ON [t].[BrandingId] = [e].[brandingId]
ORDER BY [e].[BrandingSiteTitle], [e].[brandingId]
Microsoft.Data.Entity.Query.Internal.SqlServerQueryCompilationContextFactory: Error: An exception occurred in the database while iterating the results of a query.
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'EventId1'.
Apart from this, is there a way to load related entities without using the "Includes" ? If I do not use include and use the standard LINQ query, the related entities are loaded as NULL
UPDATE
I'm now getting an invalid column error - i noticed in my previous code I hadn't used virtual on the ICollection in brand
now i can't figure out why is it generating EventId1 column in the SQL
EF 7 version is 1.0.0-rc1-final
UPDATE-2
After playing around with the code the Exception changed to circular dependency exception in code given the exact same code as above - I don't know why it was generating the invalid column name earlier (EventId1)
Answering my own question here - figured it out-
the 2 entities used here, I've used fully defined relationships in the EF 7
- however the JSON serializer doesn not like that,as this createsa circular dependancy - Brand Contains Events List, and each event also contains the parent brand property -
so the solution here was to add [JsonIgnore] attribute to relationship properties on the child
updated Events class:
[Table("tblEvents")]
public class Event
{
public int EventId { get; set; }
[Column("eventActive")]
public bool Active { get; set; }
[Column("eventName")]
public string Name { get; set; }
public DateTime EventCloseDate {get;set;}
public int PaxAllocationLimit { get; set; }
//navigation properties
[JsonIgnore]
[Column("brandingId")]
public virtual int BrandId { get; set; }
[JsonIgnore]
public virtual Brand Brand { get; set; }
//public virtual ICollection<Session> Sessions { get; set; }
}
Related
I'm implementing asp.net core project. I have 3 tables Apiapp, ApiAppHistory and EntityType. There are three fields with the names SentType, Status and Reason in ApiAppHistory and those fields are of kind Id (int type) in APIApphistory. I joined ApiApp and ApiAppHistory tables in order to get those three fields from ApiAppHistory but because they are of kind int and are unclear when showing the result to the user, I join them with EntityType table which has their related name. In the select part of my query, in addition to ApiApp fields I also need to have SentType, Status and Reason value fields.
Here below is my incomplete query:
var qq = _context.Apiapp
.Include(a => a.Api)
.Include(a => a.Application)
.Include(a => a.Data);
var t12 = (from r in qq
from b in _context.ApiAppHistory
from s in _context.EntityType
where r.LastRequest== b.Id && b.SentType == s.Id
&& b.Reason == s.Id
&& b.Status == s.Id
select new { r, s.name for Reason, s.name for
SentType ,s.name for Status});
I want in select part of my query, obtain name of the fields that I specified from the EntityType table. However, I don't know how to do it. I appreciate if someone helps me.
Here is my EntityType table:
Here are my APIAppHistory and EntityType class model:
public partial class ApiAppHistory
{
public int Id { get; set; }
public int? SentType { get; set; }
public int? Reason { get; set; }
public int? Status { get; set; }
public virtual Apiapp ApiApp { get; set; }
public virtual EntityType StatusNavigation { get; set; }
public virtual EntityType SentTypeNavigation { get; set; }
public virtual EntityType ReasonNavigation { get; set; }
}
public partial class EntityType
{
public EntityType()
{
ApiAppHistoryStatusNavigation = new HashSet<ApiAppHistory>();
ApiAppHistorySentTypeNavigation = new HashSet<ApiAppHistory>();
ApiAppHistoryReasonNavigation = new HashSet<ApiAppHistory>();
}
public int Id { get; set; }
public string Name { get; set; }
public string EntityKey { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistoryStatusNavigation { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistorySentTypeNavigation { get; set; }
public virtual ICollection<ApiAppHistory> ApiAppHistoryReasonNavigation { get; set; }
}
}
Let's take such classes:
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public string ExtraProp { get; set; }
}
public class Parent
{
public int Id { get; set; }
public string Text { get; set; }
public Child Child { get; set; }
public string ParentExtraProp { get; set; }
}
public class ChildVo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ParentVo
{
public int Id { get; set; }
public string Text { get; set; }
public ChildVo Child { get; set; }
}
Automapper mapping:
Mapper.CreateMap<Child, ChildVo>();
//.ForSourceMember(x => x.ExtraProp, o => o.Ignore()); //does not help
//.IgnoreAllNonExisting(); //does not help
Mapper.CreateMap<Parent, ParentVo>();
and query in Linq to Nhibernate:
var test = Session.Query<Parent>()
.Where(x => x.Id == myId)
.ProjectTo<ParentVo>()
.ToList();
ProjectTo selects only columns (properties) which are defined in ParentVo (not all properties from Parent class) - that's great. But is selects all columns (properties) from my Child class, despite the fact that they are not defined in ChildVo.
Why does Automapper ignore my nested property mapping? Is it possible to use all defined mappings during projection?
While I'm not familiar with nhibernate, the same test you've performed here works fine in Entity Framework. In EF you can see the query which has been generated before executing it - try doing this and seeing if it shows the additional column.
public class TestContext : DbContext {
public DbSet<Parent> Parents { get; set; }
}
var query = testContext.Parents.ProjectTo<ParentVo>();
Console.WriteLine(query.ToString());
This produces the following output (note no ExtraProp):
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Text] AS [Text],
CASE WHEN ([Extent2].[Id] IS NOT NULL) THEN 1 END AS [C1],
[Extent1].[Child_Id] AS [Child_Id],
[Extent2].[Name] AS [Name]
FROM [dbo].[Parents] AS [Extent1]
LEFT OUTER JOIN [dbo].[Children] AS [Extent2] ON [Extent1].[Child_Id] = [Extent2].[Id]
This makes me think that the problem is not AutoMapper specifically, but without seeing the generated query it's hard to tell.
I am struggling to get an Item by ID using the asynchronous API of SQLite.Net Async PCL. Here is my model class
public class Invoice : IEntityBase
{
public Invoice()
{
LineItems = new List<LineItem>();
DateCreated = DateTime.Now;
}
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public int Term { get; set; }
public bool Paid { get; set; }
public decimal Total { get; set; }
public string Notes { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
}
And the LineItems that has a One to Many relationship here
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public int Qty { get; set; }
[ForeignKey(typeof(Invoice))]
public int InvoiceId { get; set; }
[ManyToOne]
public Invoice Invoice { get; set; }
Here is the constructor:
public SQLiteAsyncConnection DbConnection;
public InvoiceDatabase(ISQLitePlatform platform, string databasePath)
{
if (DbConnection == null)
{
var connectionAsync = new Func<SQLiteConnectionWithLock>(() =>
new SQLiteConnectionWithLock
(
platform,
new SQLiteConnectionString(databasePath, false)
)
);
DbConnection = new SQLiteAsyncConnection(connectionAsync);
DbConnection.CreateTableAsync<Invoice>();
DbConnection.CreateTableAsync<LineItem>();
}
}
Other CRUD methods (Insert, GetALL) is working except getting an Invoice by ID, and both Visual Studio and Xamarin Studio are not giving me any useful stacktrace.
Here is the Get Method
private readonly InvoiceDatabase _database;
public InvoiceRepository(ISQLitePlatform platform, string databasePath)
{
if (_database == null)
{
_database = new InvoiceDatabase(platform, databasePath);
}
}
public async Task<Invoice> GetInvoice(int id)
{
var result = await _database.DbConnection.Table<Invoice>()
.Where(t => t.Id == id)
.FirstOrDefaultAsync();
return result;
}
I am passing in the Android implementation of SQLite, and like I said the Database is created but I am unable to get the Invoice object back, I even tried
public Task<Invoice> GetInvoiceWithChildren(int id)
{
return _database.DbConnection.GetWithChildrenAsync<Invoice>(id);
}
Any Help will be greatly appreciated.
After three days of chasing shadows it turned out that it is just a very simple thing that is tripping me up. I am tying to save a List of objects like so
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
I missed the part of the documentation that repeats the fact that SQLite.Net is a lightweight ORM - that point could not be stressed enough so you will have to remove your full size ORM hats such EF. So after reading from the SQLite-Net Extension documentation which says
Text blobbed properties
Text-blobbed properties are serialized into a text property when saved and deserialized when loaded. This allows storing simple objects in the same table in a single column.
Text-blobbed properties have a small overhead of serializing and deserializing the objects and some limitations, but are the best way to store simple objects like List or Dictionary of basic types or simple relationships.
I change my proptery like so and everything is now working as expected. Off now to dealing with the nuances of Async and Await
[TextBlob("LineItemBlobbed")]
public List<LineItem> LineItems { get; set; }
public string LineItemBlobbed { get; set; }
Models:
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Resource
{
[Key]
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public string ResourceDescription { get; set; }
}
public class UserResource
{
[Key, Column(Order=0)]
public int UserId { get; set; }
[Key, Column(Order=1)]
public int ResourceId { get; set; }
public int ResourceQuantity { get; set; }
}
I want to select "ResourceName" from Resource model and "ResourceQuantity" from UserResource model for a given "UserId". Also, once selected, do I need a brand new model to carry only those two specified columns?
Also note that UserResource model has a composite key so I am confused as to how to make the join... Is this right?
var userResources =
from r in imDB.Resources
join ur in imDB.UserResources
on r.ResourceId equals ur.ResourceId
select new { r.ResourceName, ur.ResourceQuantity };
Hence you're using Code first you can create your models are as below by using EF conventions.
public class User {
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Resource {
public int Id { get; set; }
public string ResourceName { get; set; }
public int ResourceQuantity { get; set; }
public virtual ICollection<User> Users {get;set;}
}
Then EF will generate your junction table is as UsersResources.You don't need to create additional model as you did.EF will look after that.
When using POCOs with EF, if you mark your navigation properties as
virtual you can use additional EF supports like Lazy Loading. So in
general use a virtual keyword in navigation properties considered to
be a good practice.
UPDATE
You may try something like below:
Method 1 : Method based syntax
imDB.Resources.Where(r => r.Users.Any(u => u.UserId == userId))
Method 2 : Query based syntax
from r in imDB.Resources
from u in r.Users
where u.UserId == userId
select r;
I hope this will help to you.
I have this POCO and I want to return a list of the users in a particular company.
public class Company
{
public AccreditedCompany()
{
this.Branches = new HashSet<Branch>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int CompanyId { get; set; }
public bool Active { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
}
public class Branch
{
public Branch()
{
this.Users = new HashSet<User>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int BranchId { get; set; }
public int CompanyId { get; set; }
public string Name { get; set; }
public string ContactName { get; set; }
public virtual Company Company { get; set;}
public virtual ICollection<User> Users { get; set; }
}
public class User
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), ScaffoldColumn(false)]
public int UserId { get; set; }
public int BranchId { get; set; }
public string ComputerSN { get; set; }
public string CameraSN { get; set; }
public virtual Branch Branch { get; set; }
}
This is my LINQ query:
var company = (from u in objDataContext.Companies.Include(c=>c.Branches.Select(v=>v.Users))
where u.CompanyId == 8 select u).FirstOrDefault();
IQueryable<User> users = (from j in company.Branches select j.Users);
I have this compilation error on the second query:
Error 2 Cannot implicitly convert type
'System.Collections.Generic.IEnumerable>'
to 'System.Linq.IQueryable'. An explicit conversion exists (are
you missing a cast?)
I want to get a list of the users, similar to a plain SQL statement like
SELECT dbo.Users.* FROM Branches
INNER JOIN dbo.Users ON dbo.Branches.BranchId = dbo.Users.BranchId
INNER JOIN dbo.Companies ON dbo.Branches.CompanyId = dbo.Companies.CompanyId
WHERE (dbo.Companies.CompanyId = 8)
Thanks in advance.
Your user query could be:
IEnumerable<User> users = company.Branches.SelectMany(branch => branch.Users);
This will return all users in any branch of the company.
It looks to me like you could just use:
IQueryable<User> users = objDataContext.Users
.Where(u => u.Branch.CompanyId == 8);
I notice you have both Company and CompanyId on your Branch entity, though. That seems redundant, even though it simplifies this query slightly. You should be able to get rid of Branch.CompanyId and User.BranchId and just use the entity associations.