I'm currently testing an Entity Framework's DbContext using the In-Memory Database.
In order to make tests as atomic as possible, the DbContext is unique per test-method, and it's populated with initial data needed by each test.
To set the initial state of the DbContext, I've created a void SetupData method that fills the context with some entities that I will use in the tests.
The problem with this approach is that the objects that are created during the setup cannot be accessed by the test, because Entity Framework will assign the Ids itself, that are unknown until run-time.
To overcome this problem, I've thought that my SetupData method could become something like this:
public Fixture SetupData(MyContext context)
{
var fixture = new Fixture();
fixture.CreatedUser = new User();
context.Users.Add(fixture.CreatedUser);
context.SaveChanges();
return fixture;
}
public class Fixture
{
public User CreatedUser { get; set;}
}
As you see, it's returning an instance of what I called "Fixture". (I don't know if the name fits well).
This way, the SetupData will return an object (Fixture) with references to the entities. Thus, the test can use the created object. Otherwise, the object will be impossible to identify, since the Id isn't created until the SaveChanges is called.
My question is:
Is this a bad practice?
Is there a better way to reference initial
data?
I prefer this approach:
public void SetupData(MyContext context)
{
var user = new User() { Id = Fixture.TEST_USER1_ID, UserName = Fixture.TEST_USER1_NAME };
context.Users.Add(user);
context.SaveChanges();
}
public class Fixture
{
public const int TEST_USER1_ID = 123;
public const string TEST_USER!_NAME = "testuser";
}
Your approach is probably fine, too, but you probably will want to know the user ID somewhere in your tests and this makes it very easy to specify it in a single known location so that it won't change if for instance you later on change your test data and the order in which you add users.
This is not a bad practice. In fact it is a good approach to create readable Given-When-Then tests. If you consider:
splitting your SetupData method
renaming it
possibly changing to a extension method
public static MyContextExtensions
{
public static User Given(this MyContext #this, User user)
{
#this.Users.Add(user);
#this.SaveChanges();
return user;
}
public static OtherEntity Given(this MyContext #this, OtherEntity otherEntity)
{
// ...
}
// ...
}
you can then write (a conceptual example, details need to be reworked to match your implementation):
[Test]
public GivenAUser_WhenSearchingById_ReturnsTheUser()
{
var expectedUsername = "username";
var user = _context.Given(AUser.WithName(expectedUsername));
var result = _repository.GetUser(user.Id);
Assert.That(result.Name, Is.EqualTo(expectedUsername));
}
... and similarly for other entities.
Related
In an api I have built using dotnet 3.1, I have the Data access model for entity "Quotation" as follows.
public class QuotationDao : BaseEntity
{
public double Amount { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public string Status { get; set; }
public Guid CustomerId { get; set; }
public CustomerDao Customer { get; set; }
public virtual ICollection<QuoteItemDao> Items { get; set; }
}
When I create a new instance of the entity 'QuoteItem', I want to increase the 'amount' attribute of the 'Quotation' entity by 1. And update the database.
The implementation of the BaseController.cs is shown below.
public class BaseController<TDao, TCreateRq, TUpdateRq, TResponse> : ControllerBase
where TDao : BaseEntity where TResponse : BaseResponse
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IRepositoryBase<TDao> _repository;
private readonly IMapper _mapper;
public BaseController(IRepositoryWrapper repositoryWrapper, IRepositoryBase<TDao> repository, IMapper mapper)
{
_repositoryWrapper = repositoryWrapper;
_repository = repository;
_mapper = mapper;
}
[HttpGet]
public virtual async Task<ActionResult<PagedResponse<TResponse>>> GetAll([FromQuery] StringQueryRequest request)
{
var paginationFilter = _mapper.Map<PaginationFilter>(request);
var pagedResponse = await _repository.ToPagedList
(_repository.FindAll(request.SearchString), paginationFilter);
var mapPagination = pagedResponse.MapPagination<TResponse, TDao>(_mapper);
return mapPagination.HandleToResponse();
}
[HttpGet("{id:guid}")]
public virtual async Task<ActionResult<Response<TResponse>>> GetById(Guid id)
{
var result = await GetDtoById(id);
return result.HandleGetToResponse();
}
[HttpPost]
public virtual async Task<ActionResult<Response<TResponse>>> Create([FromBody] TCreateRq request)
{
var entity = _mapper.Map<TDao>(request);
_repository.Create(entity);
await _repositoryWrapper.SaveAsync();
var baseResponse = _mapper.Map<TResponse>(entity);
var result = new Result<TResponse>(baseResponse);
return result.HandleToResponse();
}
[HttpPut("{id:guid}")]
public virtual async Task<ActionResult<Response<TResponse>>> UpdateById([FromRoute] Guid id,
[FromBody] TUpdateRq updateRq)
{
var getResult = await GetDtoById(id);
if (getResult.IsNone)
{
return getResult.HandleGetToResponse();
}
var value = await _repository.FindById(id);
//override the current DB objet from the values received from the request
//Not replacing the full object from the requests as some fields may be missing from the update RQ model (eg user password)
var entity = _mapper.Map(updateRq, value);
_repository.Update(entity);
await _repositoryWrapper.SaveAsync();
var baseResponse = _mapper.Map<TResponse>(entity);
var result = new Result<TResponse>(baseResponse);
return result.HandleToResponse();
}
[HttpDelete("{id:guid}")]
public virtual async Task<ActionResult<Response<TResponse>>> DeleteById([FromRoute] Guid id)
{
var getResult = await GetDtoById(id);
if (getResult.IsNone)
{
return getResult.HandleGetToResponse();
}
var baseResponse = getResult.ValueUnsafe();
var entity = _mapper.Map<TDao>(baseResponse);
_repository.Delete(entity);
await _repositoryWrapper.SaveAsync();
var result = new Result<TResponse>(baseResponse);
return result.HandleToResponse();
}
private async Task<Option<TResponse>> GetDtoById(Guid id)
{
var findById = await _repository.FindById(id);
return _mapper.Map<TResponse>(findById);
}
}
I cant figure out a way to implement this and I'd be grateful if someone could give some help.
This is the problem with relying on a purely Generic approach. Generic implies that regardless of what you pass in, they can be treated within the scope of the Generic class as identical. That said, as a base implementation, what you have isn't bad, but you are going to hit some limitations since a Generic implementation represents a "lowest common denominator" in terms of leveraging what EF can bring to the table.
Your issue can be addressed by structuring your controllers around aggregate roots and performing operations through those roots. The trouble you will find when working with related entities is that your controllers will need to know about these relationships in order to ensure required details are eager loaded to work with. You can leverage a Generic base class for controllers and repositories, but the actual controllers and repositories would be scoped around the aggregate root such as the Quotation. Adding quotation items would be done through its root (Quotation) rather than having something like a QuotationItemController and QuotationItemRepository. The goal of the QuotationController would be to support methods that can load a Quotation with it's respective items and have a method like AddQuotationItem. AddQuotationItem would then load the Quotation by ID, eager loading the items, validate the input for a QuotationItem, Create the QuotationItem, append it to the quote.Items, and increment the quote's Amount before saving the changes.
The key here would be to not think of fitting everything into a Generic pattern, but more-so leveraging a Generic if needed for elements of the controller or repositories etc. that are identical.
Some other tips: Which mapper are you using? If it is Automapper then consider using ProjectTo<TDestination>(config) rather than Map<TDestination>() when projecting to the view model. The benefit here is that the projection works across the IQueryable rather than introducing the overhead of fetching Entities and counting on related entities to be eager loaded or waking the performance troll that is lazy loading. This will be problematic with methods like FindAll if that is returning IEnumerable<TEntity> but if it is returning IQueryable<TEntity> then you should be set. Passing FindAll to something like ToPagedList won't save performance hits if FindAll is returning IEnumerable. When converting back from a view model to a DTO, provided your entities are tracked you should avoid using Update and just use Automapper's
mapper.Map(updateRq, value) which will copy the values from source to destination. If Destination is a tracked entity, then just call SaveChanges and EF will build an appropriate UPDATE statement for just the values that changed if any values actually changed. (Update will generate an UPDATE statement for all values even if nothing actually changed.)
That Update pattern is more a case of using:
var dao = mapper.Map<TEntity>(dto);
context.Update(dao);
context.SaveChanges();
which I would never recommend using over:
var dao = context.Entities.Single(x => x.Id == dto.Id);
mapper.Map(dto, dao);
context.SaveChanges();
As the later pattern validates that the dto passed in has a corresponding entity, Automapper should be configured to only copy across allowed properties according to configured rules, then SaveChanges would produce an efficient UPDATE SQL statement only if anything actually changed.
I am using the UnitOfWork pattern to abstract database access in my Asp.Net application. Basically I follow the UnitOfWork pattern approach described here:
https://chsakell.com/2015/02/15/asp-net-mvc-solution-architecture-best-practices/
However, I'm struggling to understand, how I will get the Id of a newly added item. Like if I want to add a new customer to my Customer repository, how will I get the customer id? The problem is that Add and Commit are decoupled, and the Id is not known until after Commit.
Is there a way to get the id of an added item, using the UnitOfWork pattern?
My approach is as follows. Simply continue working with the added entity as an object. So instead of returning it's ID, return the added object itself. Then, at some point (typically in the controller) you will call UoW.Commit(); and as a result, the Id property of the added entity will contain the updated value.
At this point, you can start using the Id property and for example store it in a cookie as you said.
Note that I dont want my EF model classes to propagate to my domain layer
I have done a workaround. I think it works pretty well
When you want a repository, for example of DbCars, and you insert a new DomainCar you want to get that Id that was only generated when SaveChanges() is applied.
public DomainCar //domain class used in my business layers
{
public int Id{get;set;}
public string Name{get;set;}
}
public DbCar //Car class to be used in the persistence layer
{
public int Id{get;set;}
public string Name{get;set;}
public DateTime CreatedDate{get;set;}
public string CreatedBy{get;set;}
}
First you create a generic IEntity interface and a class implementing it:
public interface IEntity<T>
{
T Id { get; }
}
public class Entity<T> : IEntity<T>
{
dynamic Item { get; }
string PropertyName { get; }
public Entity(dynamic element,string propertyName)
{
Item = element;
PropertyName = propertyName;
}
public T Id
{
get
{
return (T)Item.GetType().GetProperty(PropertyName).GetValue(Item, null);
}
}
}
Then in your add method of the repository you return a IEntity of the type of your Id:
public IEntity<int> AddCar(DomainCar car)
{
var carDb=Mapper.Map<DbCar>(car);//automapper from DomainCar to Car (EF model class)
var insertedItem=context.CARS.Add(carDb);
return new Entity<int>(insertedItem,nameof(carDb.Id));
}
Then , somewhere you are calling the add method and the consequent Save() in the UnitofWork:
using (var unit = UnitOfWorkFactory.Create())
{
IEntity<int> item =unit.CarsRepository.AddCar(new DomainCar ("Ferrari"));
unit.Save(); //this will call internally to context.SaveChanges()
int newId= item.Id; //you can extract the recently generated Id
}
The problem here is that the id is generated by the database, so we need to call SaveChanges so that the database generates the id and EntityFramework will fix the entity up with the generated id.
So what if we could avoid the database roundtrip?
One way to do this is to use a uuid instead of an integer as an id. This way you could simply generate a new uuid in the constructor of your domain model and you could (pretty) safely assume that it would be unique across the entire database.
Of course choosing between a uuid and an integer for the id is an entire discussion of its own: Advantages and disadvantages of GUID / UUID database keys But at least this is one point in favor of a uuid.
Unit of work should be a transaction for the entire request.
Simply just return the person id from the newly created object.
Depending on what technology you are using for your data access this will differ, but if you are using Entity Framework, you can do the following:
var person = DbContext.Set<Person>().Create();
// Do your property assignment here
DbContext.Set<Person>().Add(person);
return person.Id;
By creating the Person instance this way, you get a tracked instance that allows for lazy loading, and using the Id property, as it will be updated when SaveChanges is called (by ending your unit of work).
Instead of IDENTITY, I use SEQUENCE at database level. When a new entity is being created, first, I get the next value of the sequence and use it as Id.
Database:
CREATE SEQUENCE dbo.TestSequence
START WITH 1
INCREMENT BY 1
CREATE TABLE [dbo].[Test](
[Id] [int] NOT NULL DEFAULT (NEXT VALUE FOR dbo.TestSequence),
[Name] [nvarchar](200) NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([Id] ASC)
)
C#:
public enum SequenceName
{
TestSequence
}
public interface IUnitOfWork : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
void Commit(SqlContextInfo contextInfo);
int NextSequenceValue(SequenceName sequenceName);
}
public class UnitOfWork : MyDbContext, IUnitOfWork
{
...
public void Commit(SqlContextInfo contextInfo)
{
using (var scope = Database.BeginTransaction())
{
SaveChanges();
scope.Commit();
}
}
public int NextSequenceValue(SequenceName sequenceName)
{
var result = new SqlParameter("#result", System.Data.SqlDbType.Int)
{
Direction = System.Data.ParameterDirection.Output
};
Database.ExecuteSqlCommand($"SELECT #result = (NEXT VALUE FOR [{sequenceName.ToString()}]);", result);
return (int)result.Value;
}
...
}
internal class TestRepository
{
protected readonly IUnitOfWork UnitOfWork;
private readonly DbSet<Test> _tests;
public TestRepository(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
_tests = UnitOfWork.Set<Test>();
}
public int CreateTestEntity(NewTest test)
{
var newTest = new Test
{
Id = UnitOfWork.NextSequenceValue(SequenceName.TestSequence),
Name = test.Name
};
_tests.Add(newTest);
return newTest.Id;
}
}
I don't think there is a way to do that unless you break the pattern and pass in some extra information about the newly created entity.
Since the Id will only be allocated since commit is successful and if you don't have information about which entities were created/updated/deleted, its almost impossible to know.
I once did it using the code below (I don't recommend it though but I use it for this need specifically)
public string Insert(Person entity)
{
uow.Repository.Add(entity); //public Repository object in unit of work which might be wrong
Response responseObject = uow.Save();
string id = entity.Id; //gives the newly generated Id
return id;
}
My solution is returning Lazy<MyModel> by repository method:
public class MyRepository
{
// ----
public Lazy<MyModel> Insert(MyModel model)
{
MyEntity entity = _mapper.MapModel(model);
_dbContext.Insert(entity);
return Lazy<MyModel>(()=>_mapper.MapEntity(entity));
}
}
And in the domain:
Lazy<MyModel> mayModel = unitOfWork.MyRepository.Insert(model);
unitOfWork.Save();
MyModel myModel = myModel.Value;
To expand on Martin Fletcher his answer:
EF Core generates (depending on the db provider) a temporary value for the generated id, once you add the entity to the DbContext, and start tracking it. So before the unit of work is actually committed via SaveChanges(). After SaveChanges() is called, the DbContext will actually fix up all placeholder ids with the actual generated id.
A nice example (which I quote from this answer):
var x = new MyEntity(); // x.Id = 0
dbContext.Add(x); // x.Id = -2147482624 <-- EF Core generated id
var y = new MyOtherEntity(); // y.Id = 0
dbContext.Add(y); // y.Id = -2147482623 <-- EF Core generated id
y.MyEntityId = x.Id; // y.MyEntityId = -2147482624
dbContext.SaveChangesAsync();
Debug.WriteLine(x.Id); // 1261 <- EF Core replaced temp id with "real" id
Debug.WriteLine(y.MyEntityId); // 1261 <- reference also adjusted by EF Core
More information:
https://learn.microsoft.com/en-us/ef/core/change-tracking/explicit-tracking#generated-key-values
https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations#primary-keys
Another option is to generate the keys on the client side (this is possible with for example UUID-based primary keys). But this has been discussed in other answers.
I am currently developing a project in MVC 3. I've separated my concerns so there are projects such as Core, Repository, UI, Services etc. I have implement the Repository, UnitOfWork and most importantly the State pattern.
I am using Entity Framework 4.3 to persist my data and I have come across a rather annoying situation involving the persistence of the current state. Below are some class examples:
public class Request
{
public int RequestId { get; set; }
public State CurrentState { get; set; }
}
public abstract class State
{
[Key]
public string Name {get; set;}
public virtual void OpenRequest(Request request)
{}
public virtual void CloseRequest(Request request)
{}
}
public class RequestIsOpenState : State
{
public RequestIsOpenState()
{
this.Name = "Open";
}
public override void CloseRequest(Request request)
{
request.CurrentState = new RequstIsClosedState();
}
}
public class RequestIsClosedState : State
{
public RequestIsClosedState()
{
this.Name = "Closed";
}
public override void OpenRequest(Request request)
{
request.CurrentState = new RequstIsOpenState();
}
}
Using the above example I will get a primary key violation exception because it tries to create a NEW state in the States table.
Because the state change is done within the domain layer, I can't just 'get' the state from the repository and set it using the foreign key by doing something like this:
Request request = unitOfWork.RequestRepository.Find(1);
request.CurrentState = unitOfWork.StateRepository.Find("Closed");
I'm aware I have the option of not mapping the state property, and persist a string property in the request class and then convert them back and forth through a factory on a get and set when the entity is hydrated (see this answer).
All I want to do is persist the state class, so when the request is returned I can access the state methods immediately without having loads of EF stuff polluting my domain layer just to handle one persistence issue. Another benefit of which would be it gives me the added bonus of having a table in SQL to query against known states.
I think you can improve it by caching the State instances creating it only once, to avoid making the list each time and avoid the foreach:
public static class StateFactory
{
private static Dictionary<string, State> statesCache = FindAllDerivedStates();
public static State GetState(string stateTypeName)
{
return statesCache[stateTypeName];
}
private static Dictionary<string, State> FindAllDerivedStates()
{
var derivedType = typeof(State);
var assembly = Assembly.GetAssembly(typeof(State));
return assembly.GetTypes().Where(t => t != derivedType && derivedType.IsAssignableFrom(t))
.Select(t => (State)Activator.CreateInstance(t))
.ToDictionary(k => k.Name);
}
}
I've made some progress by simplifying the factory back to basics and by implementing it in such a way that you would never really know that a factory is being used. Although It's not what I was looking for, it is so refined and streamlined the only downside is I still don't have a list of ALL states within the SQL database, there are however many possible work arounds for this. Anyway... my compromise:
The State Factory:
public static State GetState(string stateTypeName)
{
var list = FindAllDerivedStates();
dynamic returnedValue = new NullState();
foreach(var state in list)
{
if(state.Name == stateTypeName) returnedValue = (State)Activator.CreateInstance(state);
}
return returnedValue
}
private static List<Type> FindAllDerivedStates()
{
var derivedType = typeof(State);
var assembly = Assembly.GetAssembly(typeof(State));
return assembly.GetTypes().Where(t => t != derivedType && derivedType.IsAssignableFrom(t)).ToList();
}
Now the request needs two properties, a persisted string and a State class. Make sure the State class is not mapped.
public class Request
{
public string StateString { get; set; }
[NotMapped] or [Ignore]
public State CurrentState
{
get
{
return StateFactory.GetState(this.StateString);
}
set
{
this.State = value.GetType().Name;
}
}
}
Now because of the new simplistic implementation, saving the state is as easy as;
request.CurrentState = new OpenState();
and getting the state will always return the methods. Without any extra work you can return an entity and excess the properties. For example if you want output the public string;
request.CurrentState.StateName;
Now I've still got to implement a little work around to add a list of states to my SqlDb but that's not the end of the world. It seems this is the only solution. Or should I say best solution. I'll keep my eyes peeled for a better version.
I have a class that uses linq to access the database. Some methods call others. For example:
class UserManager
{
public User[] getList()
{
using(var db = new MyContext())
{
return db.Users.Where(item => item.Active == false);
}
}
public User[] addUser(string name)
{
using(var db = new MyContext())
{
db.Users.InsertOnSubmit(new User() { id = Guid.NewId(), name = name, active = false ...});
}
return getList();
}
...
In the call to addUser I am required to return the new list. (I know as it stands it isn't a great design, but I have eliminated detail for simplicity.) However, the call to getList creates a second data context.
I could pad this out with extra methods, viz:
public getList()
{
using(var db = new MyContext())
return getList(db);
}
public getList(MyContext db)
{
...
}
Then replace my call in addUser so as to keep the same data context.
I seem to see this type of thing a lot in my code, and I am concerned with the cost of creating and releasing all these data contexts. Does anyone have an opinion as to whether it is worthwhile putting in the extra work to eliminate the creation and deletion of these contexts?
Microsoft provides the following advice/recommendation to not reuse DataContext instances http://msdn.microsoft.com/en-us/library/bb386929.aspx
Frequently Asked Questions (LINQ to SQL)
Connection Pooling
Q. Is there a construct that can help
with DataContext pooling?
A. Do not try to reuse instances of
DataContext. Each DataContext
maintains state (including an identity
cache) for one particular edit/query
session. To obtain new instances based
on the current state of the database,
use a new DataContext.
You can still use underlying ADO.NET
connection pooling. For more
information, see SQL Server Connection
Pooling (ADO.NET).
It is ok to reuse for different parts of the same logical operation (perhaps by passing the data-context in as an argument), hut you shouldn't reuse much beyond that:
it caches objects; this will grow too big very quickly
you shouldn't share it between threads
once you've hit an exception, it gets very unwise to reuse
Etc. So: atomic operations fine; a long-life app context; bad.
What I usually do is create a class the you could call something like DataManager with all data functions as members. This class creates an instance of MyContext on its constructor.
class DataManager
{
private MyContext db;
public DataManager() {
db = new MyContext();
}
public User[] getList()
{
return db.Users.Where(item => item.Active == false);
}
public User[] addUser(string name)
{
db.Users.InsertOnSubmit(new User() { id = Guid.NewId(), name = name, active = false ...});
return getList();
}
}
You create an instance of this class whenever you are doing a set of operations. On a Controller, for instance, you could have this class as a member. Just don't make a global var out of it, instantiate and dispose when you are done with it.
I'm using NHibernate + Fluent to handle my database, and I've got a problem querying for data which references other data. My simple question is: Do I need to define some "BelongsTo" etc in the mappings, or is it sufficient to define references on one side (see mapping sample below)? If so - how? If not please keep reading.. Have a look at this simplified example - starting with two model classes:
public class Foo
{
private IList<Bar> _bars = new List<Bar>();
public int Id { get; set; }
public string Name { get; set; }
public IList<Bar> Bars
{
get { return _bars; }
set { _bars = value; }
}
}
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
}
I have created mappings for these classes. This is really where I'm wondering whether I got it right. Do I need to define a binding back to Foo from Bar ("BelongsTo" etc), or is one way sufficient? Or do I need to define the relation from Foo to Bar in the model class too, etc? Here are the mappings:
public class FooMapping : ClassMap<Foo>
{
public FooMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.HiLo("1");
Map(c => c.Name).Not.Nullable().Length(100);
HasMany(x => x.Bars).Cascade.All();
}
}
public class BarMapping : ClassMap<Bar>
{
public BarMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.HiLo("1");
Map(c => c.Name).Not.Nullable().Length(100);
}
}
And I have a function for querying for Foo's, like follows:
public IList<Foo> SearchForFoos(string name)
{
using (var session = _sessionFactory.OpenSession())
{
using (var tx= session.BeginTransaction())
{
var result = session.CreateQuery("from Foo where Name=:name").SetString("name", name).List<Foo>();
tx.Commit();
return result;
}
}
}
Now, this is where it fails. The return from this function initially looks all fine, with the result found and all. But there is a problem - the list of Bar's has the following exception shown in debugger:
base {NHibernate.HibernateException} = {"Initializing[MyNamespace.Foo#14]-failed to lazily initialize a collection of role: MyNamespace.Foo.Bars, no session or session was closed"}
What went wrong? I'm not using lazy loading, so how could there be something wrong in the lazy loading? Shouldn't the Bar's be loaded together with the Foo's? What's interesting to me is that in the generate query it doesn't ask for Bar's:
select foo0_.Id as Id4_, foo0_.Name as Name4_ from "Foo" foo0_ where foo0_.Name=#p0;#p0 = 'one'
What's even more odd to me is that if I'm debugging the code - stepping through each line - then I don't get the error. My theory is that it somehow gets time to check for Bar's during the same session cause things are moving slower, but I dunno.. Do I need to tell it to fetch the Bar's too - explicitly? I've tried various solutions now, but it feels like I'm missing something basic here.
This is a typical problem. Using NHibernate or Fluent-NHibernate, every class you use that maps to your data is decorated (which is why they need to be virtual) with a lot of stuff. This happens all at runtime.
Your code clearly shows an opening and closing of a session in a using statement. When in debugging, the debugger is so nice (or not) to keep the session open after the end of the using statement (the clean-up code is called after you stop stepping through). When in running mode (not stepping through), your session is correctly closed.
The session is vital in NH. When you are passing on information (the result set) the session must still be open. A normal programming pattern with NH is to open a session at the beginning of the request and close it at the end (with asp.net) or keep it open for a longer period.
To fix your code, either move the open/close session to a singleton or to a wrapper which can take care of that. Or move the open/close session to the calling code (but in a while this gets messy). To fix this generally, several patterns exist. You can look up this NHibernate Best Practices article which covers it all.
EDIT: Taken to another extreme: the S#arp architecture (download) takes care of these best practices and many other NH issues for you, totally obscuring the NH intricacies for the end-user/programmer. It has a bit of a steep learning curve (includes MVC etc) but once you get the hang of it... you cannot do without anymore. Not sure if it is easily mixed with FluentNH though.
Using FluentNH and a simple Dao wrapper
See comments for why I added this extra "chapter". Here's an example of a very simple, but reusable and expandable, Dao wrapper for your DAL classes. I assume you have setup your FluentNH configuration and your typical POCO's and relations.
The following wrapper is what I use for simple projects. It uses some of the patterns described above, but obviously not all to keep it simple. This method is also usable with other ORM's in case you'd wonder. The idea is to create singleton for the session, but still keep the ability to close the session (to save resources) and not worry about having to reopen. I left the code out for closing the session, but that'll be only a couple of lines. The idea is as follows:
// the thread-safe singleton
public sealed class SessionManager
{
ISession session;
SessionManager()
{
ISessionFactory factory = Setup.CreateSessionFactory();
session = factory.OpenSession();
}
internal ISession GetSession()
{
return session;
}
public static SessionManager Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly SessionManager instance = new SessionManager();
}
}
// the generic Dao that works with your POCO's
public class Dao<T>
where T : class
{
ISession m_session = null;
private ISession Session
{
get
{
// lazy init, only create when needed
return m_session ?? (m_session = SessionManager.Instance.GetSession());
}
}
public Dao() { }
// retrieve by Id
public T Get(int Id)
{
return Session.Get<T>(Id);
}
// get all of your POCO type T
public IList<T> GetAll(int[] Ids)
{
return Session.CreateCriteria<T>().
Add(Expression.In("Id", Ids)).
List<T>();
}
// save your POCO changes
public T Save(T entity)
{
using (var tran = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
tran.Commit();
Session.Refresh(entity);
return entity;
}
}
public void Delete(T entity)
{
using (var tran = Session.BeginTransaction())
{
Session.Delete(entity);
tran.Commit();
}
}
// if you have caching enabled, but want to ignore it
public IList<T> ListUncached()
{
return Session.CreateCriteria<T>()
.SetCacheMode(CacheMode.Ignore)
.SetCacheable(false)
.List<T>();
}
// etc, like:
public T Renew(T entity);
public T GetByName(T entity, string name);
public T GetByCriteria(T entity, ICriteria criteria);
Then, in your calling code, it looks something like this:
Dao<Foo> daoFoo = new Dao<Foo>();
Foo newFoo = new Foo();
newFoo.Name = "Johnson";
daoFoo.Save(newFoo); // if no session, it creates it here (lazy init)
// or:
Dao<Bar> barDao = new Dao<Bar>();
List<Bar> allBars = barDao.GetAll();
Pretty simple, isn't it? The advancement to this idea is to create specific Dao's for each POCO which inherit from the above general Dao class and use an accessor class to get them. That makes it easier to add tasks that are specific for each POCO and that's basically what NH Best Practices was about (in a nutshell, because I left out interfaces, inheritance relations and static vs dynamic tables).