Im hoping to get your help here. Im very new to EF and am having some troubles. I am using the Database First approach and have a database in Azure that I have to retreive data from.
[DataContract]
[Table("A")]
public class AgencyDC
{
[DataMember]
[Key]
public string AID { get; set; }
public string AName { get; set; }
public string GeneralEmailAddress { get; set; }
public string WebsiteURL { get; set; }
[DataMember]
[ForeignKey("AID")]
[IgnoreDataMember]
public virtual AExtensionDC AExtension { get; set; }
}
[DataContract]
[Table("AExtension")]
public class AExtensionDC
{
[DataMember]
[Key]
public string AID { get; set; }
[DataMember]
public bool? IsActive { get; set; }
public bool? IsOptedOut { get; set; }
public DateTime? LastUpdated { get; set; }
}
I am trying to use EF6 to retreive my records using DBSets in my context..
public List<ADataCcontract> GetAllAs()
{
using (AContext _aCtx = new AContext())
{
var mylist = _aCtx.A.Include("AExtension").ToList();
return mylist;
}
}
Now, I should be getting back 547 records back with only 1 of them having the AExtension navigational property having content within. The other 546 records should contain NULL. However, for some reason, I am only getting what appears to be a record that has a match in both tables. In SQL speak, I kind of just want a left join so that I return ALL rows from AE entity and OPTIONALLY matches in AE.
I hope this makes sense.
If possible, if you have a fix, could you please post an example I could referent? I am really stuck.
I think this SO Answer might get you most of the way? https://stackoverflow.com/a/4299667/78551
Basically Include does a left outer join or left join as 'outer' is actually optional in SQL.
A left join / inner join will be performed by ´.Include´ if your fields have/lack of nullability.
To review your query put a breakpoint and check this value:
var myQuery = _aCtx.A.Include("AExtension").ToTraceString();
Related
not sure what I've done wrong. I cannot, no matter what I do, and what posts I try to follow, get EF Eager loading to work. I don't know If I have done something wrong well before hand... but nothing works. Not any style of include, or disabling lazy loading... i just cannot get it.
I have an Agent model
public class Agent
{
[Key]
public int AgentId { get; set; }
[Required]
[StringLength(50)]
public string Username { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }
[Required]
[StringLength(100)]
public string LastName { get; set; }
Then a prducer model
public class Producer
{
[Key]
public int ProducerId { get; set; }
[Required]
[StringLength(254)]
public string Name { get; set; }
public int StreetNumber { get; set; }
[StringLength(254)]
public string StreetName { get; set; }
[StringLength(254)]
public string City { get; set; }
public int StateId { get; set; }
public virtual State State { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
And then i have another model/table to link the two
public class AgentProducer
{
public int AgentProducerId { get; set; }
public int ProducerId { get; set; }
public int AgentId { get; set; }
public virtual Producer Producer { get; set; }
public virtual Agent Agent { get; set; }
}
The goal here, would be that when i Query thr AgentProducer table, my Producer property would have the entire producer object, and that producer object would have the Country and State objects.
I dont think this matters but the producer does have FK constraints on the countryId and stateId
My setup was from a lesson i was following, where i have a repository wrapper holding everything
public class RepositoryContext : DbContext
{
public RepositoryContext(DbContextOptions<RepositoryContext> options) : base(options)
{
}
public DbSet<Producer> Producers { get; set; }
public DbSet<Agent> Agents { get; set; }
}
The above item is held in a repository wrapper, that has a repository implementing a specific interface for each model type in it.
The problem Im having is whether i query with method syntax or LINQ, i cannot get everything to be included in the query, and end up having to do a bunch of extra steps to get certain info.
So far the closest i got was with LINQ, in which I would get the AgentProducer item to return with the Producer object set - however inside that producer, the COuntry and State were null, and I need that info.
I tried things like:
*** (Worth noting "AgentProducer" here is a DBSet... not sure if thats correct or not? I dont seem to have options like "ThenInclude" that ive seen in other answers.
_repoWrapper.Repo.AgentProducer.Include(i => i.Producer).Where(i => i.AgentId == filter.AgentId);
This gives me absolutely nothing - even the producer is null - before even making it to my country/state problem.
I tried
var res = _repoWrapper.Repo.AgentProducer.Include("Producer").Where(i => i.AgentId == filter.AgentId);
Same null result.
(from ap in _repoWrapper.Repo.AgentProducer.Include(i => i.Producer)
where ap.AgentId == filter.AgentId
select ap);
Same null.
The only thing that has even minorly worked was:
var res = (from ap in _repoWrapper.Repo.AgentProducer
join p in _repoWrapper.Repo.Producers on ap.ProducerId equals p.ProducerId
join a in _repoWrapper.Repo.Agents on ap.AgentId equals a.AgentId
join c in _repoWrapper.Repo.Country on ap.Producer.Country.Name equals c.Name
join s in _repoWrapper.Repo.State on ap.Producer.State.Name equals s.Name
where ap.AgentId == filter.AgentId
orderby p.Name descending
select new AgentProducer
{
AgentProducerId = ap.AgentProducerId,
Producer = p
});
Which fills out the producer, because of the manual join and set on the object. However, A) This isnt really eager loading, and B) using this method I have no idea how i can set the country and state objects on the producer here, as they still show null. And in the object initializer i cant just assign the country and state.
Ive browsed countless approaches and I cannot get a single thing to work... so i feel like I have done something wrong earlier in the process but I have no clue what.
Can anyone help me out?
Looks like it was me being a tool.
I had not grabbed the nuget package for EntityFrameworkCore.Relational, and had not added
using Microsoft.EntityFrameworkCore;
instead I had:
using System.Data.Entity;
I have the following classes:
public class Problem
{
public Problem()
{
this.Questions = new HashSet<Question>();
this.Solutions = new HashSet<Solution>();
}
public int ProblemId { get; set; }
public string Title { get; set; }
public string Note { get; set; }
public virtual ICollection<Question> Questions { get; set; }
public virtual ICollection<Solution> Solutions { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public int ProblemId { get; set; }
public int QuestionStatusId { get; set; }
public string Note { get; set; }
public virtual Problem Problem { get; set; }
}
public class Solution
{
public int SolutionId { get; set; }
public int Number { get; set; }
public int ProblemId { get; set; }
public bool? Correct { get; set; }
public string Text { get; set; }
public string Note { get; set; }
public virtual Problem Problem { get; set; }
}
Can someone help me with LINQ for my EF6,1 SQL Server 2012.
What I would like to do is to get a List that contains only a subset of the data. In this case I would like the Notes properties in Problem, Question and Solution Entities to not be fetched from the database.
Note the Question and Solution tables are connected to the Problem table. I'm not 100% sure of this but I think this means I don't need to add an .Include.
Ideally I would like the selects that EF causes to be issues to not include the Notes column.
You can use table splitting feature of EF. Create a Problem(PK+all fields except for Notes) and a ProblemNotes(PK+Notes) entities. Then querying against Problem should satisfy your needs.
http://msdn.microsoft.com/en-us/data/jj715645.aspx
With Entity Framework table splitting you can separate the properties that might contain very large amount of data into a separate entity and only load it when required.
You might use .Select(...) to make avoid fetching redundantly data from db. The code below illustrates how to fetch list of Problems with only ProblemId and Title fields:
var result = context.Problems.Select(problem => new { ProblemId = problem.ProblemId , Title = proble.Title }).ToList();
Using of .Select above will generate SQL query "SELECT p.ProblemId,p.Title from dbo.Problems as p".
Using of .List will retrieve data (it will not be dependent on context anymore )
Your might cast resulted set to Problem type ,eg:
var newResult = result.Select(x=>new Problem() { ProblemId = x.ProblemId, Title = x.Title } )
I read about querying database using the entity framework
var result = _dbContext.SqlQuery<string>(sql, someParamSqlParameter).ToList();
What if i wanted multiple columns to be returned how could i write that type of query.
I tried this code but it gives some sql schema mapping error
var result = clsGlobalObjectRefrances.SchoolSoulController.Stt.Database.SqlQuery<LocalAccGroups>(sqlQuery).ToList();
var sqlQuery = "Select GroupId,GroupName,Level from cte_AccGroups";
Where LocalAccGroups is a class i created
class LocalAccGroups
{
public decimal GroupId { get; set; }
public string GroupName { get; set; }
int Level { get; set; }
}
Thanxxx in Advance
Your query is returning Level as well, and you haven't marked your property Level in your class as public. Mark your property as public and it should be good. Also make sure that the data type matches the one returned by query. It seems odd go a GroupId to be of type decimal.
class LocalAccGroups
{
public decimal GroupId { get; set; }
public string GroupName { get; set; }
public int Level { get; set; }
}
I think I have read every article and stack overflow question regarding this, but cannot work out the solution. Let me start out with my models
public class Entry
{
public Entry ()
{
DateEntered = DateTime.Now;
}
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public string Number { get; set; }
public string FbId { get; set; }
[ReadOnly(true)]
public DateTime DateEntered { get; set; }
public string AccessToken { get; set; }
//Relationsips
public Backgrounds Background { get; set; }
public Cars Car { get; set; }
}
public class Backgrounds
{
public int Id { get; set; }
public string Name { get; set; }
public string Filename { get; set; }
}
public class Cars
{
public int Id { get; set; }
public string Name { get; set; }
public string FileName { get; set; }
}
Now in my controller, I am updating the entry. Like follows
// PUT /api/entries/5
public HttpResponseMessage Put(Entry entry)
{
if(ModelState.IsValid)
{
_db.Entries.Attach(entry);
_db.Entry(entry).State = EntityState.Modified;
_db.SaveChanges();
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
My Entry model gets updated correctly, but if for eg entry.Background.Name changes, this will not be persisted to the database. My controller is accepting the entire entry model including its relationships => Backgrounds and Cars. However any value that is changed to the relationship is not updated or reflected. Any elegant solution without having to query the database then updating? I dont want to have any extra queries or lookups before I update.
Thanks
Tyrone
You must manually tell EF about all changes done to the object graph. You told EF just about change to entry instance but you didn't tell it about any change to related entities or relations itself. There is no elegant way to solve this. You have generally two options:
You will use some DTOs instead your entities and these DTOs will have some flag like IsDirty - when you receive object graph back to your controller you will reconstruct entities from DTOs and set their state based on IsDirty. This solution needs further extensions for example if your client can also delete relations.
You will query object graph from database and merge your incoming changes to entities retrieved from database.
There are some partial solutions like forcing to save changes to all related objects by setting their state to modified and identifying new objects by Id == 0 but again these solutions work only in specific scenarios.
More complex discussion about this problem.
I'm prototyping my first MVC application, it's a simple forum. I've done part of the domain model and I'm trying to figure out how to do something that's pretty basic in SQL alone, but I can't figure it out in my application. Here are my Entities:
[Table(Name="Users")]
public class User
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int Id { get; set; }
[Column] public string Username { get; set; }
[Column] public string Password { get; set; }
[Column] public string PasswordHash { get; set; }
[Column] public string PasswordSalt { get; set; }
[Column] public string FirstName { get; set; }
[Column] public string LastName { get; set; }
public List<Forum> AllowedForums { get; set; }
[Column] public DateTime LastLogin { get; set; }
[Column] public DateTime MemberSince { get; set; }
}
[Table(Name="Forums")]
public class Forum
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int Id { get; set; }
[Column] public int ParentId { get; set; }
[Column] public string Title { get; set; }
[Column] public string Description { get; set; }
[Column] public bool IsGlobal { get; set; }
[Column] public int DisplayOrder { get; set; }
}
I also have a linking table called AllowedForums that looks like:
userid forumid
1 4
In order to select the forums that a user is allowed to view and forums where IsGlobal == true I'd do this in SQL:
SELECT * FROM Forums
LEFT OUTER JOIN AllowedForums ON Forums.id = AllowedForums.Forumid
WHERE AllowedForums.Userid = 1
OR Forums.IsGlobal = 1
How should I populate the
public List<Forum> AllowedForums
field using C#/Linq to SQL?
Should AllowedForum be a value object with its own table mapping? That seems like overkill but I could easily join on it. I looked briefly at EntitySet but the simple example I saw didn't seem to fit. It feels like there should be an elegant way to get a collection of Forum objects for each User, but I can't come up with any. BTW, I'm new to C# & OO. I should also mention that since these are the early stages of the app, I'm open to changing the structure/relationships of the entities or tables if there's a better approach I'm not seeing.
You should have another Entity class (probably should be internal) that mirrors your AllowedForums table in the database. Now I'm assuming your User table and your Forums table both have PK/FK relationships to this AllowedForums table. Therefore, there should be an internal property on the User class that looks like this:
internal EntitySet<AllowedForums> AllowedForumsRelationships
{
get;set;
}
Or something like that. This should be on both the User and Forums class. Your AllowedForums class will have two properties on it. One for User and one for Forum. (If you use the LINQ to SQL designer, all this will happen for you automatically).
Once you have that, if you want to get all the AllowedForums for a user you can do something like this:
public IList<Forum> AllowedForums
{
get
{
var result = new List<Forum>();
foreach(var relationShip in this.AllowedForumsRelationships)
{
result.Add(relationShip.Forum);
return result;
}
}
}
This is some rough code I just banged out, and I'm not sure it's 100% accurate, but I think you'll get the idea. Basically you're dealing with a many to many relationship which is always a pain.
EDIT: I just messed with this idea with the Northwind Database with these tables:
Orders
OrderDetails
Products
There's a many to many relationship there: An order can have multiple products, and a product can belong to many orders. Now say you want to get all products for an order:
public partial class Order
{
public IList<Product> Products
{
get
{
var list = new List<Product>();
foreach (var item in this.Order_Details)
{
list.Add(item.Product);
}
return list;
}
}
}
That works, so it should work in the scenario you're talking about as well.
Something like:
var AllowedForums = from f in ForumsTable
join af in AllowedForumsTable on f.Id equals af.forumid into temp
from aft in temp.DefaultIfEmpty()
where (f.IsGlobal == 1 || aft.userid == 1)
select f;