How to create a NHibernate proxy object with some initiliazed fields (other than Id)? - nhibernate

I want to create an object proxy, similar to what ISession.Load is returning, but with some fields initialized. For other properties, when accessed, the proxy will fetch the entire object from database.
Consider the following example:
public class User
{
protected User() {
}
public User(int id, string username, string email) {
// ...
}
// initialize the following fields from other datasources
public virtual int Id { get; set; }
public virtual string UserName { get; set; }
public virtual string Email { get; set; }
// the rest of fields when accessed will trigger a select by id in the database
public virtual string Field1 { get; set; }
public virtual string Field2 { get; set; }
public virtual DateTime Field3 { get; set; }
public virtual ISet<Comment> Comments { get; set; }
}
The Id, UserName, Email are well-known in my case, so I could create an object proxy containing these fields, and for the others leave the default proxy behavior. In addition to throwing an exception if this id is not found in the database, i could throw an exception if preinitialized fields do not match or overwrite them silently. I am using NHibernate.ByteCode.Castle for proxy factories.
Edit:
The purpose for this is to be able to have some projection properties from an entity which can be queried elsewhere (say. a lucene index) and to avoid database calls. Then instead of wrapping these fields in a custom component class containing only these subset of properties, I want to use the proxy object directly so that I am able to load the rest of fields if needed. In the best case scenario I wouldn't hit the database at all, but in some corner cases I'd like to access other fields, too. The SELECT N+1 problem's impact can be greatly reduced by using batching.
An hypothetical version of code I want to use would be:
// create User object proxy with some fields initialized
var user = Session.Load<User>(5, new { UserName = "admin", Email = "admin#company.com" });
Console.WriteLine(user.Id); // doesn't hit the database
Console.WriteLine(user.UserName); // doesn't hit the database
Console.WriteLine(user.FullName); // doesn't hit the database
if (somecondition) {
Console.WriteLine(user.Field1); // fetches all other fields
}

You can specify an eager fetch inside the query to actually retrieve the needed associations. This could be done in different ways depending on what query style ( Criteria,Hql or LINQto NH ) you are using. But the key is changing the fetch mode.

for non-collection properties, I wouldn't do that;
the cost of prefetching them from the DB when you load your entity is (usually) so small that I wouldn't even bother.
for collection properties, just mark the collection fetch strategy as 'lazy=true'.
The only case where I would think about doing something like that is when I have a very large number of properties which I don't need (in your example- say Field1..Field20).
In that case I would either:
1. Define those properties together as a component, or
2. create a DTO for fetching only a subset of your entity's properties.

specifying lazy = "true" (or Not.LazyLoad() for Fluent NHib) on properties Field1, Field2, Field3, Comments mappings may help, though not sure about Select N+1 issue.
another way to go is specifying lazy = "false" for UserName, Email

Related

What is the recommended way to do partial updates with PATCH in ServiceStack?

I am building a RESTful API using the ServiceStack framework. A lot of the resources that I need to update are quite big, with up to 40 attributes per class, so I would like to do partial updates instead of replacing the entire resource. Often the client will only need to update one or two attributes out of the 40, so I would like to just send a JSON body consisting of the few attributes.
Since all combinations of attributes are possible, it is not feasible to make an "Update" class per class as suggested here: https://github.com/ServiceStack/ServiceStack/wiki/New-Api#patch-request-example
In the Microsoft ASP.NET WebAPI OData package there is a Delta class that takes a subset of a class and updates the resource based on this subset (http://www.strathweb.com/2013/01/easy-asp-net-web-api-resource-updates-with-delta/). This is the functionality I would like to have, as I will be having quite a few classes so a generic method would be best.
Basically, if I have a class
public class MyClass {
public int a { get; set; }
public int b { get; set; }
...
public int z { get; set; }
}
I would like to update a resource of MyClass with a PATCH request with body
{"a":42,"c":42}
Is there a standard or recommended way to accomplish this with ServiceStack?
Declare any scalar values in your DTO as nullable. This will allow you to determine which fields were actually sent in the request:
public class MyClass {
public int? a { get; set; }
public int? b { get; set; }
public int? c { get; set; }
// etc.
// object-type properties are already nullable of course
public string MyString { get; set; }
}
Now if a client sends a partial request, like so:
{ "a": 1, "b": 0 }
You'll be able to determine which properties were actually sent when inspecting your DTO:
myClass.a == 1
myClass.b == 0
myClass.c == null
myClass.MyString == null
etc.
Set up a PATCH route for your DTO and implement a Patch method in your service:
public object Patch(MyClass request)
{
var existing = GetMyClassObjectFromDatabase();
existing.PopulateWithNonDefaultValues(request);
SaveToDatabase(existing);
...
}
PopulateWithNonDefaultValues is key here. It will copy values from your request object onto the database entity, but will only copy properties that are not the default values. Thus, if a value is null, it won't copy it, because the client didn't send a value for it. Notice that it will copy an integer value of zero though, because we made it a nullable int, and the default value for a nullable int is considered by this method to be null, not zero. Declaring your DTO properties as nullable shouldn't cause much of a hassle in the rest of your code.
Note that this approach works easily with JSON. If you need to support XML requests/responses, you may need need to do some additional work with DataContract/DataMember attributes to insure that nulls are handled correctly.
While esker's response is fine I would like to add that it might not be enough for nullable fields - since you don't know if the deserializer or the user have created that null field.
One approach would be to peek at the raw request.
A different approach is to ask the user to provide additional request (querystring) parameter to clearly specify which fields to patch.
Something like: patch_fields=name,description,field3
The bonus of that approach is that the end user has more control over the patching and is not overriding a value by mistake (because he used the original entity and forgot to clear some fields)

remove from collection without load all collection data. confused which collection mapping to use

I have a many-to-many relationship between Assignment and User
When trying to delete an user from an assignment, I see all users are loaded in the collection.
How to I avoid that?
public class User
{
public virtual int Id { get; private set; }
public virtual IList<Assignment> Assignments { get; set; }
}
public class Assignment
{
public virtual int Id { get; private set; }
public virtual ICollection<User> Users { get; set; }
}
Mappings:
HasManyToMany(user => user.Assignments).Table("UserToAssignment").ParentKeyColumn("UserId").ChildKeyColumn("AssignmentId").Inverse().ExtraLazyLoad();
HasManyToMany(productAssignment => productAssignment.Users).AsSet().Table("UserToAssignment").ParentKeyColumn("AssignmentId").ChildKeyColumn("UserId").LazyLoad();
Calling code:
assignment.Users.Remove(user)
Initially I used Bag instead of Set for Assignment mapping, but when updating it, it was deleting and then reinserting alot of rows in the AssignmentsToUsers table. So I changed to using Set.
But now I see a problem with using Set: it brings all data in memory.
What is the recommended way of doing this?
You can't avoid this and I would ignore it if performance is acceptable. If performance is a problem, there are three ways I can think of to tackle it:
If the other side of the collection (User.Assignments) is lighter weight then remove the assignment from the user instead.
Model the many-to-many table and delete the object directly. You would have to be certain that the Users collection is not going to be loaded prior to this because the in-memory representation will still contain the deleted record.
Direct delete using SQL -- this has the same caveat as #2.
You should use extra lazy mode also for Assignment.Users.

EF4 and intentionally returning only *some* of the properties of an entity

Folks, I know I didn't phrase that title very well, but here's the scenario.
I have a WinForm UI tier, and a WCF middle tier, serving up my EF4 entity objects, which are (of course) mapped to my database tables. Everything works fine.
One of my objects is the Client - and in the Client db table are three varbinary(max) fields for PDF documents. So my entity object has three Byte() properties, one for each document.
But when I load up an initial grid listing the Clients, it's going to drag ALL that PDF data from the MT - making a much bigger payload than I generally need.
With DataSets, I'd write my SQL to not include the PDF binary - but I'd include a Boolean flag field for each to indicate whether there IS one to download if the user wants it. Then I'd load the PDFs via a separate call as needed.
With EF4 - what's the best pattern for this?
First, I'm thinking to put the documents into a child-table/child-objects, so I don't pull it across the tier with the Client. One problem solved.
Second, I suppose I could use partial classes to extend my Client entity object to have the three Boolean properties I want.
Am I on the right track?
I think you have three options:
1) Create a custom class which you project the properties you want into:
public class MySpecialSelection
{
public int ID { get; set; }
public string Name { get; set; }
// more
public bool HasPDFDoc1 { get; set; }
public bool HasPDFDoc2 { get; set; }
public bool HasPDFDoc3 { get; set; }
}
using (var context = new MyContext())
{
var mySpecialSelectionList = context.MyEntities.Where(...some predicate...)
.Select(e => new MySpecialSelection
{
ID = e.ID,
Name = e.Name,
// ...
HasPdfDoc1 = (e.PdfDoc1 != null),
HasPdfDoc2 = (e.PdfDoc2 != null),
HasPdfDoc3 = (e.PdfDoc3 != null),
}).ToList();
// ...
}
Instead of a "named" object you can also project into anonymous types.
Note: This doesn't attach any full model entity to the context, so you won't have any change tracking of entities.
2) Table splitting: It means that you split your single entity into two separate classes which are related by a navigation property. You can map then both entities to a single table in the database. It allows you to load the navigation properties (for instance the binary fields) on request (by lazy, eager or explicite loading). Details about this for EF4.0 are here and for EF4.1 here.
3) Your own proposal: Create separate tables and separate entities which are linked by navigation properties and FK constraints.

Is there something analogous on NHibernate regarding Entity Framework's navigation property?

Is there something analogous on NHibernate regarding Entity Framework's navigation property? For example, instead of:
s.Save(new Product { Category = s.Get<Category>("FD"), Name = "Pizza" });
I wish I could write:
s.Save(new Product { CategoryId = "FD", Name = "Pizza" });
Can I inform NHibernate not to use the Product's Category property as a mechanism to save the Product's category? I want to use CategoryId instead(Read: I don't want to use DTO). Entity Framework seems able to facilitate avoiding DTO patterns altogether, while at the same time offering the full benefit of ORM(can avoid joins using navigation properties). I want the EF's offering the best of both worlds(lean mechanism for saving objects, i.e. no need to retrieve the property's object) and navigation mechanism for querying stuff
Sample from EF: http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx
public class Category
{
public virtual string CategoryId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
}
public class Product
{
public virtual int ProductId { get; set; }
public virtual string Name { get; set; }
public virtual string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
[UPDATE]
Regarding James answer, I tried seeing the NHibernate's actions in SQL Server Profiler.
// this act didn't hit the Category table from the database
var c = s.Load<Category>("FD");
// neither this hit the Category table from the database
var px = new Product { Category = c, Name = "Pizza" };
// this too, neither hit the Category table from the database
s.Save(px);
Only when you actually access the Category object that NHibernate will hit the database
Console.WriteLine("{0} {1}", c.CategoryId, c.Name);
If I understand your question, you want to save a Product with a Category without hitting the database to load the Category object. NHibernate absolutely supports this and you almost have the right code. Here is how you do it in NHibernate:
s.Save(new Product { Category = s.Load<Category>("FD"), Name = "Pizza" });
This will not hit the database to fetch the actual Category, but it will simply save a Product with the correct Category.Id. Note that you don't need (and I would recommend getting rid of Product.CategoryId).
Now why does this work with session.Load(), but not session.Get()... With session.Get(), NHibernate has to return the object or null. In .NET, there is no way for an object to replace itself with null after the fact. So NHibernate is forced to go to the database (or L1 cache) to verify that the "FD" Category actually exists. If it exists, it returns an object. If not, it must return null.
Let's look at session.Load(). If the object is not present in the database, it throws an exception. So NHibernate can return a proxy object from session.Load() and delay actually hitting the database. When you actually access the object, NHibernate will check the database and can throw an exception at that point if the object doesn't exist. In this case, we're saving a Product to the database. All NHibernate needs is the Category's PK, which it has in the proxy. So it doesn't have to query the database for the Category object. NHibernate never actually needs to hydrate an actual Category object to satisfy the save request.

Inheritance with Fluent NHibernate produces double results

I have the following scenario:
public class Login
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
}
public class User : Login
{
public IList<Account> Accounts { get; set; }
}
If I have two maps (ClassMap<Login> and ClassMap<User>), all queries returns double results - one per maps I'd guess.
Is it possible to avoid this? I don't have a discriminator value. There are a lot more properties on the user, so I'd like to be able to just get a sub set of these via the login.
Since User extends Login, querying Login will, by default, return User instances too.
To avoid this, polymorphism="explicit" must be used in the XML mappings.
For Fluent mappings, use Polymorphism.Explicit().
Perhaps specifying different data tables for the two entities Login and User might do the trick, so you would have to explicitely query either the Login or User depending on your needs. Otherwise, Diego Mijelshon's answer sounds pretty good!