FluentNHibernate - overriding already existing automappings - postgresql

I'm trying hard to find a solution to be able to override the automapping of my entity.
The flow of execution is that AutoMapping (using conventions) occurs first and then mapping overrides are executed.
My entity "Signature" is already mapped by automapper (do not confuse with Automapper library!) and I want to change the db type of some columns.
If I do something like this:
public class SignatureMap : IAutoMappingOverride<Signature>
{
public void Override(AutoMapping<Signature> mapping)
{
mapping.Map(x => x.SignType).CustomSqlType("character varying");
mapping.Map(x => x.Status).CustomSqlType("integer").Nullable();
}
}
I get NHibernate errors with NpgsqlParameterCollection (index out of range) when trying to execute an insert to the table.
This probably occurs because the mapping.Map function just adds another mapping to the collection instead of overriding one that already exists (I examined the FluentNHibernate source code).
What is the proper way to override the Sql type using IAutoMappingOverride ?

There is nothing wrong with override syntax you use, make sure you:
1) actually reference your overrided mappings in configuration: .UseOverridesFromAssemblyOf<SignatureMap>();
2) verify that NHibernate treat your DB schema as you expect. You may use something like new SchemaExport(config).Create(true, false); for this, this will output sql to console.
If 1 and 2 are ok, than problem might be in your insert code.

Related

How to write an extension for the Entity Framework Core

The actual thing that I need is an effective Delete method for the entities. In other words I would like to be able to write
cntx.Orders.Where(item => item.Category == "Custom1").Delete();
and that is supposed to delete all the records from the table Orders where the Category column value is equal to "Custom1". I don't really care if it will do it right away or after calling cntx.SaveChanges(). And, yes, the query is supposed to be efficient, something like
DELETE FROM Orders WHERE Category = "Custom1"
I know about at least 3 extension libraries for the Entity Framework Core which advertise such abilities but non of them work for Android. Now, I'm thinking how difficult it actually is to write a Delete extension method myself. Can anybody help me with an example? Apparently I should be able to add something to the expression tree which will be called by the framework and in my turn I would generate "DELETE FROM Orders" and then "Where(item => item.Category == "Custom1")" would be replaced by the "WHERE Category = "Custom1""
So, apparently everything should start from
public static class QueryExtension {
public static void Delete<T>(IQueryable<T> objThis) {
// The big mystery is what to call here to ensure that "DELETE FROM [TableName]"
// is entered to the right place of the expression tree and then
// we somehow need to execute the complete statement here or delegate it to SaveChanges
}
}
I sort of realize that translation of the expression tree into a SQL statement happens somewhere in the expression visitor. That is most likely wrapped into some kind of statement compiler of the Entity Framework. I have no idea where all those entry points to write an extension like I need.

Logging all Entity Framework queries in the debug window in DB-First Approach

I want to log the Entity Framework queries in my debug window. I could do that with the following line:
myContext.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
But how can I do that for all my queries in different functions and in different files?
Do I have to write this line everywhere?
Or is there a way to do this by writing a particular line of code to log every query at a single place.
As suggested, I have written the code in the constructor of the context but it's not working.
public partial class EkartEntities : DbContext
{
public EkartEntities() : base("name=EkartEntities")
{
Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
}
Am I doing something wrong?
Also, it is not duplicate of How to make EF log sql queries globally?
as the post contains the answer of Code-First approach where we can simply modify our constructor.
You can install global logger by adding the following class to the project containing your DbContext derived class:
class MyDbConfiguration : System.Data.Entity.DbConfiguration
{
public MyDbConfiguration()
{
AddInterceptor(new System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter(
s => System.Diagnostics.Debug.WriteLine(s)));
}
}
The class represents the so called Code-based configuration and in this particular case is used to automatically register DatabaseLogFormatter with the specified Action<string> for all DbContext derived types and instances in the project that contains it.
I think it is better that you can refer to use SQL Server Profiler to capture all the queries to database.
If you are developing locally, SQL Profiler will be ideal for you.
Whatever kind of Linq Queries or Raw SQL Query can be captured by the profiler.

EntityFramework how to Override properties

I've just started using EF in VS2010. That thing is just amazin'.
I frankly can't understand something. For example I have EntityType with property, they generated from database structure.
Now, I have to simply override that property in my code. I don't need to save value of the property back into DB, but everytime when it gets read from DB it should be substituted with run-time calculated value.
Of course I can create derived class based on my EntityType but I've tried and found kinda difficulties, I'm not sure this is kinda right way to do. Anyway even when I try to change the whole EntityType to Abstract, damn Visual Studio doesn't want to validate that and says something like:
"Error 2078: The EntityType 'AssetsModel.Asset' is Abstract and can be mapped only using IsTypeOf."
"Error 2063: At least one property must be mapped in the set mapping for 'Assets'"
What the hell is this suppose to mean I dunno..
Any ideas?
The best approach would be to use Partial Classes and then create a new ReadOnly property to calculate the value in the getter.

In ADO.Net Data Services how do I check if an entity is already in the context?

I have an ADO.Net Data Service that I am using to do a data import. There are a number of entities that are linked to by most entities. To do that during import I create those entities first, save them and then use .SetLink(EntityImport, "NavigationProperty", CreatedEntity). Now the first issue that I ran into was that the context did not always know about CreatedEntity (this is due to each of the entities being imported independently and a creation of a context as each item is created - I'd like to retain this functionality - i.e. I'm trying to avoid "just use one context" as the answer).
So I have a .AddToCreatedEntityType(CreatedEntity) before attempting to call SetLink. This of course works for the first time, but on the second pass I get the error message "the context is already tracking the entity".
Is there a way to check if the context is already tracking the entity (context.Contains(CreatedEntity) isn't yet implemented)? I was thinking about attempting a try catch and just avoiding the error, but that seems to create a new CreatedEntity each pass. It is looking like I need to use a LINQ to Data Services to get that CreatedEntity each time, but that seems innefficient - any suggestions?
I think you should look at the EntityState property of your entity.
Only if it is of the value EntityState.Detached than you have to add it to your context.
Do not forget the following remark:
This enumeration has a FlagsAttribute
attribute that allows a bitwise
combination of its member values.
I would create a extension method:
public static class EntityObjectExtensions
{
public static Boolean IsTracked(this EntityObject self)
{
return (self.EntityState & EntityState.Detached) != EntityState.Detached;
}
}
When trying to check whether the context was tracking the entity that I wanted to update (or add) I was pretty disapointed when I found that the context.Entites.Contains(currentItem) didn't work.
I got around it using:
if (context.Entities.Where(entities => entities.Entity == currentItem).Any())
{
this.service.UpdateObject(currentItem);
}

Entity Framework: Re-finding objects recently added to context

I am using the entity framework and I'm having a problem with "re-finding" objects I just created... basically it goes like this:
string theId = "someId";
private void Test()
{
using(MyEntities entities = new MyEntities())
{
EntityObject o = new EntityObject();
o.Id = theId;
entities.AddToEntityObject(o);
CallSomeOtherMethod(entities);
}
}
void CallSomeOtherMethod(MyEntities ents)
{
EntityObject search = ents.EntityObject.FirstOrDefault(o => o.Id == theId);
if(search == null)
{
Console.WriteLine("wha happened???");
}
}
(no guarantee the code works btw - it's all from my head)
Why doesn't the query "find" the EntityObject that was just created?
If I call SaveChanges() after the AddToEntityObject it works (which doesn't surprise me) but why doesn't it pull from the cache properly?
I'm still green on this stuff so I'm hoping that there's some really easy thing that I'm just overlooking...
Thanks
The newly added object is in the local DataSource, since it's not persisted yet in the database,
so you may say:
EntityObject search = ents.EntityObject.FirstOrDefault(o => o.Id == theId) ??
ents.EntityObject.Local.FirstOrDefault(o => o.Id == theId);
This happens because ents.EntityObject.WhatEver always queries the datasource. This is a design decision. They do it this way, because else they would have to execute the query against the datasource, against the local cache and then merge the results. As one of the developers pointed out in a blog (cannot remember where exactly) they were unable to handle this consistently.
As you can imagine there are a lot of corner an edge cases you have to handle properly. You could just find a id you created locally, created by someone else in the database. This would force you to be prepared to handle conflicts on (almost) every query. Maybe they could have made methods to query the local cache and methods to query the datasource, but that is not to smart, too.
You may have a look at Transparent Lazy Loading for Entity Framework. This replaces the normal code generator and you get entities that populate their related entity collections and entity references automatically on access. This avoids all the
if (!Entity.ReleatedEntities.IsLoaded)
{
Entity.RelatedEntities.Load();
}
code fragments. And you can query the collections because they are always implicitly loaded. But this solution is not perfect, too. There are some issues. For example, if you create a new entity and access a collection of related entities, you will get an exception because the code is unable to retrieve the related entities from the database. There is also an issue concerning data binding and may be some more I am not aware of.
The good thing is that you get the source code and are able to fix the issues yourself and I am going to examine the first issue if I find some time. But I am quite sure that it will not be that easy to fix, because I expect some case were just not hitting the database if the entity has just been created is not the expected behavior.
I was in the same situation. I wrote this extension method that at least for me solves the problem (I don't have issues with i.e conflicts in my context...)
public static IEnumerable<T> WhereInclAdded<T>(this ObjectSet<T> set, Expression<Func<T, bool>> predicate) where T : class
{
var dbResult = set.Where(predicate);
var offlineResult = set.Context.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(entry => entry.Entity).OfType<T>().Where(predicate.Compile());
return offlineResult.Union(dbResult);
}
The extension method bellow is to DbSet<>
public static T TryAttach<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate) where T : class
{
T found = dbSet.Local.SingleOrDefault(predicate.Compile());
if (found == null) dbSet.Attach(entity);
return found ?? entity;
}
How to use:
contextInstance.MyEntity.TryAttach(entityInstance, e => e.ID == entityInstance.ID);
btw: I love generics!
I have recently struggled with this same question. I'm posting this answer 2 years after the question was asked in hopes that this bit of code may help someone searching for an answer.
I have basically implemented an extension method (as suggested by Alex James) called "Find" that operates in the same way that "Where" does, but "Find" also checks the ObjectContext to see if there are any Added entities that satisfy the given predicate. This allows you to find an entity even if it hasn't been saved to the database yet.
Find returns an IQueryable(of T) so that you can use it just like any other LINQ operator.
<Extension()>
Public Function Find(Of T As Class)(ByVal OSet As ObjectSet(Of T), _
ByVal predicate As Expression(Of Func(Of T, Boolean))) _
As System.Linq.IQueryable(Of T)
'Check the object context for Added objects first.
Dim AddedContextObjects = OSet.Context.ObjectStateManager _
.GetObjectStateEntries(EntityState.Added) _
.Select(Function(entity) entity.Entity).OfType(Of T)()
Dim Cpredicate = predicate.Compile
Dim MatchingObjects As New List(Of T)
For Each TObj As T In AddedContextObjects
If Cpredicate.Invoke(TObj) Then
MatchingObjects.Add(TObj)
End If
Next
'Now include a query to retrieve objects from the DB.
Dim DBObjects = OSet.Where(predicate)
If MatchingObjects.Count > 0 Then
'We found some added objects in the context.
'We want to return these objects as well as any Objects in DB
'that satisfy the predicate.
Return MatchingObjects.Union(DBObjects).AsQueryable
Else
'We didn't find any added objects in the context,
'so we just return the DB query.
Return DBObjects
End If
End Function
You have a number of options. You could extend the ObjectContext with another partial class to make your own mechanism for retrieving recently Added information.
Or you could just put an extension method on the ObjectContext that looks through the ObjectContext.ObjectStateManager looking for 'added' ObjectStateEntries, and then use LINQ to Objects to find what you are looking for.
Entity Framework 6
As per EF Docs Dbset always query against the database.
Note that DbSet and IDbSet always create queries against the database
and will always involve a round trip to the database even if the
entities returned already exist in the context. A query is executed
against the database when:
It is enumerated by a foreach (C#) or For Each (Visual Basic)
statement. It is enumerated by a collection operation such as ToArray,
ToDictionary, or ToList. LINQ operators such as First or Any are
specified in the outermost part of the query. The following methods
are called: the Load extension method on a DbSet,
DbEntityEntry.Reload, and Database.ExecuteSqlCommand. When results are
returned from the database, objects that do not exist in the context
are attached to the context. If an object is already in the context,
the existing object is returned (the current and original values of
the object's properties in the entry are not overwritten with database
values).
When you perform a query, entities that have been added to the context
but have not yet been saved to the database are not returned as part
of the result set. To get the data that is in the context, see Local Data
If a query returns no rows from the database, the result will be an
empty collection, rather than null.
Below is a simple snippet with local data:
await dbContext.Entity
.Where(e => e.Title.Contains("Text"))
.LoadAsync();
var locaEntities = dbContext.Entity.Local;
dbContext.Entity.Add(new Entity {});
// call save post atomic operation is finished.
await dbContext.SaveChangesAsync();