I have a model -
public class EmployeeModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Designation { get; set; }
public double? Salary { get; set; }
}
and a LINQ method syntax like -
public List<EmployeeModel> GetEmployees()
{
using (var DbCon = new OfficeEntities())
{
var result = DbCon.Employee.Select(x => new EmployeeModel()
{
Id = x.Id,
Name = x.Name
//Salary = x.Salary,
//Designation = x.Designation
})
.ToList();
return result;
}
}
I have commented out salary and designation but even though it prints with
key : salary and for value i:null="true" why
result comes like this
<EmployeeModel>
<Designation i:nil="true"/>
<Id>1</Id>
<Name>Sulochana </Name>
<Salary i:nil="true"/>
</EmployeeModel>
Even though commented/removed the parameters in the query, why it is appearing in the result. Kindly help
Because you didn't include those properties in the projection.
This has a special meaning for the client to interpret, it's not that these fields have a null value, these fields we're not included in the projection, so their values are indeterminate.
If the client has requesting a projection with $select=Id,Name then these fields would not have been included at all, but because the client is expecting all the fields this is how the API expresses to the client that the fields we're deliberately omitted, but to satisfy the return contract the fields must be provided in some form.
This answer is assuming OP is writing an OData service, but the same concept applies with Linq to Entities in general. If the Linq expression is projecting into a model type, but not including certain fields, then those fields will have an uninitialized value on the model instances that are projected out.
You are creating an EmployeeModel object in the Select projection. Hence, Salary and Designation are being initialized with their default values, even though you didn't set values for them. Then after serializing all properties are present in the result.
If you are expecting only Id and Name in the output/result, then define a type in that shape -
public class EmployeeInfo
{
public int Id { get; set; }
public string Name { get; set; }
}
and create an object of that type in the projection -
var result = DbCon.Employee.Select(x => new EmployeeInfo()
{
Id = x.Id,
Name = x.Name
})
.ToList();
Related
I have three tables, Organization, Department, and OrganizationDepartments. here is the relationship between them.
Now I would like to join these three tables and create another object for a DTO class. This DTO object has some properties and a list of other DTOs. Here is the DTO Class.
Organization DTO:
public class OrganizationDto
{
public string Id { get; set; }
public string OrganizationName { get; set; }
public string Logo { get; set; }
public bool? IsActive { get; set; }
public IList<OrganizationDepartmentDto> OrganizationDepartments { get; set; }
}
OrganizationDepartment DTO:
public class OrganizationDepartmentDto
{
public string OrganizationId { get; set; }
public string OrganizationName { get; set; }
public string DepartmentId { get; set; }
public string DepartmentName { get; set; }
}
Now I would like to write a LINQ query to get a Organization object along with all the departments related to that organization. The query is imcomplete because I don't know how can I get all the department information as list in a single query. The code is below:
var organizationInfo = (from org in _dbContext.Organizations
join orgDept in _dbContext.OrganizationDepartments on org.Id equals orgDept.OrganizationId
join dept in _dbContext.Departments on orgDept.DepartmentId equals dept.Id
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
OrganizationDepartments = //TODO:..
}
);
Can anyone help me to get the department lists of that organization's object (see the TODO:)?
If your entities are mapped correctly, and the relationships are correctly configured.
you can use .Include("OrganizationDepartment") and .ThenInclude("Department")to ensure relations are included into the generated Query.
If you insist on using Query Syntax. e.g from org in context.Organization
you can write out the query like this.
var q = (from org in _dbContext.Organizations
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
OrganizationDepartments = org.OrganizationDepartments.ToList()
}
Depending on your usecase. Sometimes you are not interested in actually showing the "many to many" table outside of the scope of your database.
so it might make more sense to actually flatten the Dto.
that query would look like
var q = (from org in _dbContext.Organizations
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
Departments= org.OrganizationDepartments.Select(t => t.Departments).ToList()
}
I have an EF Core model that has a binary field
class SomeModel {
string Id;
string otherProperty;
byte[] blob;
};
Usually, when I query the DB, I want to return a list of this Model - and then, on subsequent calls, query just a single entity, but return the blob.
I can't see a way in either data or code first to prevent EF Core paying the cost of retrieving the blob field always.
I really want to be able to say something like:
var list = await Context.SomeModels.ToListAsync();
// later
var item = await Context.SomeModels
.Where(m=>m.Id==someId)
.Include(m=>m.blob)
.FirstOrDefaultAsync();
I think I might have to put the blobs into a 2nd table so I can force a optional join.
The only way you could get a separate loading is to move the data to a separate entity with one-to-one relationship.
It doesn't need to be a separate table though. Although the most natural choice looks to be owned entity, since owned entities are always loaded with the owners, it has to be a regular entity, but configured with table splitting - in simple words, share the same table with the principal entity.
Applying it to your sample:
Model:
public class SomeModel
{
public string Id { get; set; }
public string OtherProperty { get; set; }
public SomeModelBlob Blob { get; set; }
};
public class SomeModelBlob
{
public string Id { get; set; }
public byte[] Data { get; set; }
}
Configuration:
modelBuilder.Entity<SomeModelBlob>(builder =>
{
builder.HasOne<SomeModel>().WithOne(e => e.Blob)
.HasForeignKey<SomeModelBlob>(e => e.Id);
builder.Property(e => e.Data).HasColumnName("Blob");
builder.ToTable(modelBuilder.Entity<SomeModel>().Metadata.Relational().TableName);
});
Usage:
Code:
var test = context.Set<SomeModel>().ToList();
SQL:
SELECT [s].[Id], [s].[OtherProperty]
FROM [SomeModel] AS [s]
Code:
var test = context.Set<SomeModel>().Include(e => e.Blob).ToList();
SQL:
SELECT [e].[Id], [e].[OtherProperty], [e].[Id], [e].[Blob]
FROM [SomeModel] AS [e]
(the second e.Id in the select looks strange, but I guess we can live with that)
Situation
I have searched for the answer to this extensively (on SO and elsewhere) and I am aware that there are many questions on SO by this same title.
I had a table mapping and model that were working. Then the schema was changed (I do not have direct control of the DB) such that a new Primary Key was introduced and the old Primary Key became the Foreign Key to another table. I believe this is the heart of the problem as no other entities seem to have issues
Mapping
Here is the method that maps my entity (called from OnModelCreating)
private static void MapThing(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Thing>().ToTable("ThingTable");
modelBuilder.Entity<Thing>().HasKey(p => p.Id);
modelBuilder.Entity<Thing>().Property(p => p.Id).HasColumnName("NewId");
modelBuilder.Entity<Thing>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Thing>().Property(p => p.FileName).HasColumnName("ColumnWhosNameChanged");
modelBuilder.Entity<Thing>().HasRequired(p => p.MetaDataOnThing);
}
The old PK of the table is now defined as a property on the model and it is the same name as the column (the reason it is not defined in the mapping above).
Model
Here is the Model (I have applied names that I hope will make it more clear what has changed):
public class Thing
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//This used to be the PK, its names (Property AND Column) have not changed
public int OldId { get; set; }
//The column name for FileName changed to something else
public string FileName { get; set; }
//Unchanged
public byte[] Document { get; set; }
public string ContentType { get; set; }
//Navigation Property
public ThingMetaData MetaDataOnThing { get; set; }
}
Integration test
I removed a lot of structure to, hopefully, make it clear..the test is pretty straight forward
[TestMethod]
public void ThenThingWillBePersisted()
{
var thing = new Thing()
{
OldId = metaDataObject.Id,
Document = new byte[] { 42 },
FileName = "foo.jpg",
ContentType = "image/jpeg"
};
context.Things.Add(thing);
context.SaveChanges();
}
This test produces the error "A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column:'NewId'" and the inner exception points to the NewId as being the issue. It does so on the SaveChanges() call.
Admittedly, I have a lot more experience with nHibernate than I do with Entity Framework but I am pretty sure my mappings and model are setup properly.
Has anyone seen this issue and how did you solve it?
Got a very difficult EntityFramework Code First question. I'll keep this as simple as possible.
Imagine we have n number of classes, lets start with 2 for now
public class Person
{
public string Name { get; set; }
}
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
}
Now then, what I want to do is be able to search the domain model with a single string, i.e. something like DbContext.Search( "Foo" ). The call would search both the person and address tables for a string match and would return a list populated with both Person and Address entities.
Have to say I am not entirely clear how to go about it but I am considering using DataAnnotations to do something like this
public class Person
{
**[Searchable]**
public string Name { get; set; }
}
public class Address
{
**[Searchable]**
public string AddressLine1 { get; set; }
**[Searchable]**
public string AddressLine2 { get; set; }
}
Am I on the right track?
Should I use the Fluent API instead?
Reflection?
Any and all thoughts massively appreciated.
the Find method searches only in the Primary Key column. If we don't make any column explicitly primary key column then find method will throw error. Generally EF convention takes propertyName+id as the primary key in the class. But if you want to search with Name then Make add [Key] to the property. it will become primary key and u will be able to find properties.
dbContext.Addresses.find("Foo");
Create a new object type onto which you'll project 2 types of search results:
public class Result
{
public string MainField { get; set; }
// you may have other properties in here.
}
Then find entities of each type that match your criteria, projecting them onto this type:
var personResults = DbContext.Persons
.Where(p => p.Name == "Foo")
.Select(p => new Result{MainField = p.Name});
// don't forget to map to any other properties you have in Result as well
var addressResults = DbContext.Adresses
.Where(a =>
a.AddressLine1 == "Foo" ||
a.AddressLine2 == "Foo"
).
.Select(a => new Result{MainField = a.AddressLine1 + ", " + a.AddressLine2 });
// again, don't forget to map to any other properties in Result
Then merge the lists:
var allResults = personResults.Union(addressResults).ToList();
...at which point you can sort the list however you like.
"Result" and "MainField", are rather generic; just using them because I am not thoroughly aware of your domain model.
I have the following enum and POCO class
public enum Gender
{
Male,
Female,
Unknown
}
public class Person
{
public int PersonId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public Gender? Gender { get; set; }
}
I would like to perform a "get all people" query in my repository such that it would look something like this:
return from p in _db.People
select new Model.Person
{
PersonId = p.PersonId,
LastName = p.LastName,
FirstName = p.FirstName,
Gender = p.Gender,
};
Unfortunately I get an error "Cannot implicitly convert type 'string' to 'Model.Gender'"
I would like to convert the string which is being queried from the entity framework to my Gender enum and assign it to my POCO class.
Enums are not supported in Entity Framework. There is a workaround by Alex James, but it's quite involved.
Instead, i prefer to do this:
public enum Gender : byte
{
Male = 1,
Female,
Unknown
}
public class Person
{
public int PersonId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public byte Gender { get; set; } // this is the EF model property
public Gender GenderType // this is an additional custom property
{
get { return (Gender) Gender; }
set { Gender = (byte)value; }
}
}
It's basically a hook/wrapper for the actual value. In your database, store Gender as a tinyint (which maps to byte on the conceptual side).
Then you can use a byte enum to map to and from the model property:
return from p in _db.People
select new Model.Person
{
PersonId = p.PersonId,
LastName = p.LastName,
FirstName = p.FirstName,
Gender = p.Gender, // sets byte
};
But then if you access that ViewModel, because your setting the byte field for Gender, you will also have access to the enum property GenderType.
Does that solve your problem?
The Entity Framework that I am familiar with does not provide support for enums. EF uses your query expression to create an SQL statement that it then sends to the server, if it cannot create the SQL equivalent of some operation it will throw a NotSupportedException for that operation. If you are expecting to return a small set of data you can separate from the Entity Framework by creating an object in memory using the ToArray method.
var myEntities = (from entity in _db.Entities
where /* condition */
select entity)
.ToArray();
This will create a sequence of entities in memory. Any further query statements will then be in the realm of LINQ to Objects which allows parsing of strings into enums:
return from myEntity in myEntities
select new MyDataContract
{
ID = myEntity.ID,
Gender g = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true)
};
Or you could even break it out into a foreach loop:
List<MyDataContract> myDataContracts = new List<MyDataContract>();
foreach (var myEntity in myEntities)
{
var dataContract = new MyDataContract { ID = myEntity.ID };
if (Enum.IsDefined(typeof(Gender), myEntity.Gender))
dataContract.Gender = (Gender)Enum.Parse(typeof(Gender), myEntity.Gender, true);
myDataContracts.Add(dataContract);
}
return myDataContracts.AsEnumerable();
if (Enum.IsDefined(typeof(Gender), genderstring))
Gender g = (Gender) Enum.Parse(typeof(Gender), genderstring, true);
else
//Deal with invalid string.
try
Gender = p.Gender != null ? (Gender)Enum.Parse(typeof(Gender), p.Gender) : (Gender?)null;
To parse the string as one of the enums
here's a workaround but it means changing your nice and clean POCO
http://blogs.msdn.com/b/alexj/archive/2009/06/05/tip-23-how-to-fake-enums-in-ef-4.aspx