EF - cast int(short) to string with copability Linq expression - c#

Default DTO model class:
public class Test
{
public short Id { get; set; }
public string Name { get; set; }
}
Legacy DB with name type as Number(5).
CREATE TABLE SCHEME.TABLE_NAME
(
ID NUMBER(5) NOT NULL,
NAME NUMBER(5) NOT NULL
)
Example:
public dynamic GetResult(string searchString)
{
return DbContext.Set<Test>()
.Where(x => x.Name.Contains(searchString))
.FirstOfDefault();
}
How to create mapping for field Test for available query Entity Framework? Because without normal mapping EF mean string type as normally but cannot create normally query SQL to get same data.

Related

EF Core cant translate simple where linq expression

we recently upgraded to use ef core 2.1.8, and now some of our queries are failing.
Something as simple as a where clause causes ef to evaluate it locally.
I have a language table, with a name column, i wanna select all where name is not null, but neither of these two works:
var searchQuery = from q in context.Language
where (q.Name != null) select q;
var searchQuery = context.Language.Where(x => x.Name != null);
Both are being evaluated locally. Name is a simple string / nvarchar column.
Edit:
Language is a partial class that looks like this:
public partial class Language
{
public Language()
{
Segmentation = new HashSet<Segmentation>();
SystemTranslation = new HashSet<SystemTranslation>();
}
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Culture { get; set; }
public ICollection<Segmentation> Segmentation { get; set; }
public ICollection<SystemTranslation> SystemTranslation { get; set; }
}
public partial class Language : IIdentifiable<int>, ISearchable
{
public string Name => CultureInfo.GetCultureInfo(Culture).DisplayName;
}
With the following configuration:
void IEntityTypeConfiguration<EF.Entity.Core.Language>.Configure(EntityTypeBuilder<EF.Entity.Core.Language> builder)
{
builder.HasIndex(e => e.Culture)
.HasName("IX_Culture")
.IsUnique();
}
It turns out i was trying to query on a calculated property, which of course means that ef was unable to use it server side, as no column by that name existed.

EntityFreamwork full entity and lite entity

i have table users
user table :
Id, Name , firstName , password , email , address , dateofBrith
i want to create two entity for user table one lite and other full
[Table("user")]
public class LiteUser
{
public int ID {get;set;}
public string Name {get;set;}
public int firstName{get;set;}
}
second entity
public class fullUser : LiteUser
{
public date dateofBrith {get;set;}
public string password {get;set;}
public string email {get;set;}
public string address {get;set;}
}
but not I get error about no column discriminator
is possible to do somthing like my entity are same but one have more filed then the other entity
thank you in advance for help
Unfortunately, no. You can only define one entity to one table. Instead, you'd have to do a manual .Select off of the full entity to return a custom "Lite" entry because EF needs to know all the columns that tie to a specific table from the start.
Edit: The only way around this would be to create a view and map to that instead.
You can do something like this
[Table("user")]
public class LiteUser
{
public string Name {get;set;}
public int firstName{get;set;}
}
public class fullUser : LiteUser
{
public int ID {get;set;}
public date dateofBrith {get;set;}
public string password {get;set;}
public string email {get;set;}
public string address {get;set;}
}
Use primary key public int ID {get;set;} value in the derived class
As Daniel points out, a table can be associated to a single entity definition, outside of Table Per Hierarchy inheritance, which isn't what you are looking for.
This was an old trick I used with NHibernate which isn't supported in EF.
With EF you can utilize Linq and ViewModels to avoid the need of Lite vs. Full models.
Given:
//Entity
public class User
{
public int ID {get;set;}
public string Name {get;set;}
public int firstName{get;set;}
public date dateofBrith {get;set;}
public string password {get;set;}
public string email {get;set;}
public string address {get;set;}
}
// View Models...
public class LiteUserViewModel
{
public int ID {get;set;}
public string Name {get;set;}
public int firstName{get;set;}
}
public class FullUserViewModel : LiteUserViewModel
{
public date dateofBrith {get;set;}
public string password {get;set;}
public string email {get;set;}
public string address {get;set;}
}
Querying..
//Give me a list of lite data..
var viewModels = context.Users
.Where(x => x.DateOfBirth < startDate)
.Select(x => new LiteUserViewModel
{
UserId = x.UserId,
Name = x.Name,
FirstName = x.FirstName
}).ToList();
// Give me a full user.
var viewModel = context.Users
.Where(x => x.UserId = userId)
.Select(x => new FullUserViewModel
{
UserId = x.UserId,
// ... etc ...
}).SingleOrDefault();
You can leverage libraries like AutoMapper to handle mapping entity to view model. In cases where you just want to inspect data you don't need to define a view model / DTO, just use an anonymous type. The end result is the same in that EF will execute an optimized query to just return back the data you want rather than entire entities. You can optimize view models to flatten down hierarchical data using this technique. You do need to ensure that any methods or transformations in the .Select() are pure and EF compatible because EF will attempt to translate and pass those to SQL. More complex transformations should be done in the view model itself, or utilize an anonymous type select of the raw data, followed by a ToList/Single/etc. then .Select() into the view model with appropriate transformations via Linq2Object.
One option is to use table splitting which is when you map a single table to two or more entities. The difference with your requested solution is that the "additional" properties in the "full" configuration will be represented by another entity type. Example (for EF Core; EF6 will be very similar):
public class SplitTablePrincipal
{
[Key]
public int Id { get; set; }
public string PrincipalProperty { get; set; }
// principal entity has a nav property to the dependent entity
public virtual SplitTableDependent Dependent { get; set; }
}
public class SplitTableDependent
{
[Key]
public int Id { get; set; }
public string DependentProperty { get; set; }
}
public class SplitTablePricipalConfiguration : IEntityTypeConfiguration<SplitTablePrincipal>
{
public void Configure( EntityTypeBuilder<SplitTablePrincipal> builder )
{
//builder.HasKey( pe => pe.Id );
// establish 1:? relationship w/ shared primary key
builder.HasOne( pe => pe.Dependent )
.WithOne()
.HasForeignKey<SplitTableDependent>( de => de.Id ); // FK is PK
builder.ToTable( "YourTableName" );
}
}
public class SplitTableDependentConfiguration : IEntityTypeConfiguration<SplitTableDependent>
{
public void Configure( EntityTypeBuilder<SplitTableDependent> builder )
{
//builder.HasKey( de => de.Id );
// map dependent entity to same table as principal
builder.ToTable( "YourTableName" ); // same table name
}
}
You only need to include a DbSet for the SplitTablePrincipal entity type in your DbContext. When querying, the Dependent property will not be populated by default (your "lite" configuration); you would need to eager load the property for the "full" data configuration via .Include( stp => stp.Dependent ). You could also lazy load or explicitly load the Dependent property further down the line should you so choose. For example:
dbContext.Entry( principalEntity ).Reference( p => p.Dependent ).Load();

Mongo C# IMongoCollection Design

I am using an interface as a collection type when initializing an IMongoCollection. I am using an interface class as the collection so that it can be better for testing.
public IMongoCollection<IEmployee> Employees => Database.GetCollection<IEmployee>("employee");
public interface IEmployee
{
[BsonId]
ObjectId Id { get; set; }
string Name { get; set; }
}
[BsonDiscriminator(Required = true)]
[BsonKnownTypes(typeof(Employee))]
public class Employee : IEmployee
{
public ObjectId { get; set; }
public string Name { get; set; }
}
I have a database class of Employee which implements IEmployee. When storing to the database, I have to store a type of Employee because I can't declare a new instance of IEmployee.
var emp = new Employee
{
Id = ObjectId.GenerateNewId();
Name = "Wayne Rooney";
};
// Insert into the Employees collection
await Employees.InsertOneAsync(emp);
When I want to replace/update that document, I can't because I am querying from a lower layer class of IEmployee.
await Employees.FindOneAndReplaceAsync(f => f.Id.ToString() == context.Id, g);
context in this case is the parameter of type Employee that I am passing in. g is the update document of type Employee. f in this case is type IEmployee. When I do a replace, I get a [document].Id.ToString() is not supported error.
So the question is, I'm able to insert and retrieve them, but not able to update/replace/delete a document. Any suggestions?
First, a few heads ups.
When inserting to the database, if you have specified an ObjectId as your BsonId then there is no need to manually set it.
So set the BsonId-attribute on your Id.
public class Employee : IEmployee
{
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; }
}
And then insert as such:
var emp = new Employee
{
Name = "Wayne Rooney";
};
// Insert into the Employees collection
await Employees.InsertOneAsync(emp);
A unique ObjectId will be set by itself upon inserting.
The problem itself most likely lies in the ToString()-part of your Linq-query. I'm not sure it translates well into a mongo-query. A quick work-around would be to just use something like:
var id = new ObjectId(context.Id);
await Employees.ReplaceOneAsync(f => f.Id == id, g);
This eliminates the ToString()-call and compares ObjectId's directly.
The support of Linq-queries are somewhat limited in the driver. I would advise against using them (there is also some overhead here).
The suggested, and most direct route is to use the built-in filters.
For instance:
var filter = Builders<IEmployee>.Filter
.Eq(nameof(Employee.Id), new ObjectId(context.Id));
await Employees.ReplaceOneAsync(filter, g);
nameof(Employee.Id) is C# 6, and will return "Id". If you do not have support for C# 6 then simply use "Id" instead.

Entity Framework - set model property value dynamically from a query

I have the following models:
public class A_DTO
{
[Key]
public string Id { get; set; }
**public virtual B_DTO B { get; set; }**
public virtual List<B_DTO> Bs { get; set; }
}
public class B_DTO
{
[Key]
public string Id { get; set; }
public string AId { get; set; }
public string UserId {get; set; }
[ForeignKey("AId"]
public virtual A_DTO A { get; set; }
[ForeignKey("UserId"]
public virtual User User { get; set; }
}
I am trying to get a list of object A_DTO but also including property B:
using AutoMapper.QueryableExtensions;
public IQueryable<A_DTO> GetAllA_DTO()
{
string userId = "8b6e9332-7c40-432e-ae95-0ac052904752";
return context.A_DTO
.Include("Bs")
.Include("B")
.Project().To<A_DTO>()
.Where(a => a.Bs.Any(b => b.UserId == userId));
}
How do I dynamically set this property according to set UserId and A_DTO.Id?
Here is a bag of observations in which you may be lucky enough to find your solution:
The B property in a code first model will result in there being a foreign key in the database table for A_DTOs that contains a reference to the B_DTOs table. Entity Framework will expect to own the responsibility for filling the B navigation property with an object populated with the data from the referenced row in the B_DTOs table, hence you would not be able to change it dynamically.
There is no need to use the Automapper Project method if your source type and destination type are the same. In your example they would both appear to be A_DTO. Are you sure you don't actually intend to have an entity "A" that is included in the context and "A_DTO" that is mapped from "A" via Automapper? If that is what you really want then you could have code in a .Select call mapping A.Bs.FirstOrDefault(b => b.UserId == userId) to A_DTO.B. However, you would not be able to apply filtering on the basis of the userId in an Automapper map.
Without seeing any of the Automapper Map setup code, it is difficult to get an idea of intent here.
As an aside, when using .Include it is better, in my opinion, to use the overload that takes an expression. In your case the includes would be rewritten:
.Include(a => a.B)
.Include(a => a.Bs)
Using this overload ensures that you will get compile time errors if you rename a property but fail to update the string in the .Include statement.

Entity Framework 4: How to code projection to a class type?

If I have a class like the following:
public class Customer {
public int id {get;set;}
public string name {get;set;}
public string line1 {get;set;}
public string line2 {get;set;}
public string line3 {get;set;}
public string line4 {get;set;}
}
And I only want to select the ID and Name values, leaving the rest null.
var myCustomerList = DC.Customer.Select(
p => new Customer { id = p.id, name = p.name });
I get the following error:
The entity or complex type 'MyModel.Customer' cannot
be constructed in a LINQ to Entities query.
How else would you do it? Am I required to specify all the Class's fields?
Try this:
var myCustomerList = from c in DC.Customer
select new { id = p.id, name = p.name };
The above will create an Anonymous Type.
Practical Application:
"var myCustomerList" <-- Anonymous Type.
An anonymous type with two properties "id" and "name". Also, "var" lets you create an Implicitly typed local variable. This means:
a) You didn't have to declare/write a class structure to hold a type with only those two properties;
b) You don't have to maintain that either - you can change the structure of the above query, and "it just works".
Another option is to create a CustomerInfo type:
public class CustomerInfo
{
public int Id { get; set;}
public string Name { get; set; }
}
You can't map two types directly to the same table in EF but you can easily create a view for your info type and then map to that:
CREATE VIEW vwCustomerInfo AS SELECT Id, Name FROM Customer
You then map your CustomerInfo type to your view:
public class CustomerInfoMap : EntityConfiguration<CustomerInfo>
{
public CustomerInfoMap()
{
.ToTable("vwCustomerInfo");
}
}
A side-effect of this is that EF will only retrieve the columns in the view when querying your database. When retrieving a CustomerInfo by id you'll get SQL like this:
SELECT Id, Name FROM vwCustomers WHERE id = 1
In addition, as long as your view is updatable you can update your CustomerInfo type from EF and the underlying table will be updated.

Categories