Custom getter on entity model? - entity-framework

I have an Entity with a Date property and want to create a boolean property to check if that Date is in the future or not.
public DateTime Date { get; set; }
public virtual bool IsUpcoming {
get
{
return Date >= DateTime.Now;
}
}
But when I try to run a Get on it, it throws this error:
The LINQ expression 'DbSet()
.Where(s => s.IsUpcoming)' could not be translated. Additional information: Translation of member 'IsUpcoming' on entity type 'Show' failed. This commonly occurs when the specified member is unmapped. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information
Any tips on why/how would this work?

You have to add [NotMapped] attribute
[NotMapped]
public virtual bool IsUpcoming {
get
{
return Date >= DateTime.Now;
}
}
or Ignore if you use fluent api
modelBuilder.Entity<Show>().Ignore(c => c.IsUpComing);
but you will be able to use it after you get the DB set to your application( usually after ToList()). If you try to use it in a Linq query to get data from DB you will get the exception you have got already.

Related

Fluent NHibernate Readonly property after Insert (Audit - type Data Created Updated Dates)

I HAVE to be overthinking this because it's a super common workflow just not finding the right answer. Using Fluent NHibernate over postgres and given the following simple class and mapping, how can I set the audit data in code, then secure/lock it during subsequent update calls.
public class RecordEntity
{
public virtual int Id {get;set;}
public virtual DateTime CreatedOn {get;set;}
public virtual DateTime UpdatedOn {get;set;}
}
And Mapping
public class RecordEntityMapping:ClassMap<RecordEntity>
{
public RecordEntityMapping()
{
Id(x => x.Id).GeneratedBy.Increment();
Map(x => x.CreatedOn);
Map(x => x.UpdatedOn);
}
}
then I want to be able to do something like this in my repository
...
var record = new RecordEntity();
record.CreatedOn = record.UpdatedOn = DateTime.UtcNow;
await _session.SaveAsync(record); // Created on should be properly persisted.
...
Then an update...
//record passed in from somewhere else...
record.UpdatedOn = DateTime.UtcNow;
await _session.UpdateAsync(record); // CreatedOn here will be who knows what.
...
Ok options.
I could put in a postgres rule that sets a date on insert, then set the property to be generated.insert() and .ReadOnly().
I could set up some kind of interceptor that checks whether I'm doing an update or insert, and react accordingly.
is there a way in nhibernate or postgres that says ignore if default then make sure it's always default on updates.
I know I can always make an extra call to get the data out of the db and merge the records. kind of defeats the purpose.
There's got to be an easier way. What am I missing? What other options do I have?

Extend EF 6.2 with new mapping rules

NHibernate can be extended with new implementations of IUserType, so I can customize how a mapped property is read and stored to/from the database.
An example. If I want DB null varchar to load as "n/a" string, and "n/a" string to be stored as null.
How is this possible with EF 6.2?
I am looking for a solution that doesn't break the change-tracker.
As of EF 6.2, there is no such functionality provided out of the box by the library.
If you decide to move to EF Core instead, there you can use the HasConversion functionality.
However, in your case you still wouldn't be able to use it, because there is one caveat: it can't be used to convert null values. Null always gets converted to null. From docs:
A null value will never be passed to a value converter. A null in a database column is always a null in the entity instance, and vice-versa. This makes the implementation of conversions easier and allows them to be shared amongst nullable and non-nullable properties. See GitHub issue #13850 for more information.
In that case, I suggest that instead of a Value Conversion you configure your string property to have a Backing Field. Then, you can read/write to/from the private backing field, and then have a public property handling the null value.
public class Blog
{
private string _stringFromDb;
public string MyString { get; set; }
[BackingField(nameof(_stringFromDb))]
public string MyString
{
get { return _stringFromDb ?? "n/a"; }
}
public void SetMyString(string myString)
{
// put your validation code here
_stringFromDb = myString;
}
}
In EF 6.2 the closest you could have, as a workaround, is a [NotMapped] property that can be in charge of translating the property you load from the DB.
public string StringDB { get; set; }
[NotMapped]
public string StringConverted
{
get { return MyStringProperty ?? "n/a"; }
set { MyStringProperty = value }
}
If, in addition to this, you want to hide the property being mapped to your DB by making it private, it's not as straightforward as with EF Core's backing field, but you could follow this other answer for instructions on how to achieve it.

Validate Unique Value in MVC5 and EF6

In my MVC application I have a requirement where I want user to insert Unique value in a column.
i.e.: Username should be unique in Users table.
I used [Indes(IsUnique = true)] data annotation in my model.
But when I insert duplicate value in the field it throws an exception, but I want to display an Error Message on my View saying Please try with a different Username
Please help me what should I do here?
You can use one of those:
Write your CustomValidator (ny recommendation)
[CustomRemoteValidator(ErrorMessage = #"Username already in use")]
public string Username{ get; set; }`
And override IsValid method
public override bool IsValid(object value)
{
return !(this.DbContext.Set<User>().Any(a =>
a.Username.Equals((string)value));
}
Check it in your business layer.
Check it before save entity in database by overriding SaveChanges() method.

Passing a comparison function and value as parameters into Entity Framework

This is a follow-up on question on Passing a comparison function as a parameter into Entity Framework.
I would like to pass a comparison function and a value into a search function that queries Entity Framework. The comparison function has to operate on different properties depending on the value. E.g., my data is
class DataItem
{
[Key]
public int ID { get; set; }
public bool Active { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
and I need a context method
public List<DataItem> SearchValue(Func<string, string, bool> op, string value)
{
if (value.Length < 10)
return DataItem.Where(di => di.Active && op(di.Prop1, value)).ToList();
else
return DataItem.Where(di => di.Active && op(di.Prop2, value)).ToList();
}
that I can then call like
List<DataItem> list = context.SearchValue((s1, s2) => s1 == s2, "A");
where I also need different comparison functions (all canonical).
Program compiles alright, but on running I get a "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." error.
Loading the DataItems into memory is not an option since I'll have around a billion of them. That's why I'm looking for a server-side solution. All the operations I'm using are canonical, so they can be translated into SQL queries. My question is just: how can I pass them as parameters?
This issue means that your LINQ query cannot be converted to a proper SQL query for backend execution.All LINQ to SQL or Entity framework queries get converted to SQL which is run on the backend and if they have some operation which could not be translated to SQL this error can come.
I think you should first bring your data in memory using .ToList() or .AsEnumerable() and then use 'Op' operation on that.That should solve the problem
Unfortunately you can't do it with LinqToEntities. You have to create sql query manually or call Database function...

Using subquery in poco to fill property

I am trying to use a property on a POCO that uses LINQ to ENTITY to pull the first object out of a HashSet property on the same POCO. My object contains the following:
public virtual HashSet<ScheduleWaypoint> ScheduleWaypoints { get; set; }
public ScheduleWaypoint ArrivalStation {
get {
if (this.ScheduleWaypoints != null && this.ScheduleWaypoints.Count() > 0) {
return this.ScheduleWaypoints.Where(row => row.WaypointType.Type.Trim() == "SA").OrderByDescending(row => row.ScheduledTime).First();
} else
return null;
}
}
If I were working with just one object I can't say for certain if this would work but I know that it does not work inside other linq queries. I don't have access to the ID of the ScheduleWaypoint when creating the object, only after it is populated could I possibly do that. Is there a way that I can get this to work? Right now it is telling me:
The specified type member 'ArivalStation' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported.
Is there something I can do to get access to this information on a property rather than constantly doing joins when I need the info?
Thanks.
You cannot use custom properties in linq-to-entities query. Only properties mapped directly to the database can be used = you must have sub query directly in your linq-to-entities query returning your ArrivalStation. Perhaps it can be wrapped as simple extension method:
public static IQueryable<ScheduleWaypoint> GetArrivalStation(this IQueryable<ScheduleWaypoints> waypoints, int routeId)
{
return waypoints.Where(w => w.WaypointType.Type.Trim() == "SA" && w.Route.Id == routeId)
.OrderByDescending(w => w.ScheduledTime)
.FirstOrDefault();
}
Where Route is your principal entity where way points are defined. FirstOrDefault is used because sub queries cannot use just First.