I am trying to query a view using NHibernate, but receving an empty result always.
View name: vw_lead_review_detail
Code snippet for View mapping:
[Class(NameType = typeof(LeadReviewDetail), Table = "vw_lead_review_detail", Lazy = false, Schema = "affiliate")]
public class LeadReviewDetail
{
[Id(Name = "LeadEventId", Column = "lead_event_id", UnsavedValue = "0")]
[Generator(1, Class = "assigned")]
public virtual int? LeadEventId { get; set; }
[Property(Column = "addition_input_value")]
public virtual string AdditionInputValue { get; set; }
}
Is there anything else do I need to change in this mapping class?
thank you!
Here is how to debug this:
Have your mapping been actually loaded? (NHibernate returns empty result if you query for a class that has no mapping.)
Enable NHibernate detailed logging and examine the SQL produced.
Related
I'm trying to perform a search action on my page. I have 3 tables on my database with no relation between then. I created a view model called SearchModel and I'm trying to send the query data to the view like below
I'm very new to ASP.NET*
IQueryable<SearchModel> t = Enumerable.Empty<SearchModel>().AsQueryable();
var searchD = from d in db.domains
where d.domainName.Contains(search) //search is the search string
select d;
var searchU = from u in db.users
where u.userName.Contains(search)
select u;
var searchA = from a in db.adminLists
where a.userName.Contains(search)
select a;
t.searchDomain = searchD;
t.searchAdmin = searchA;
t.searchUsers = searchU;
return view(t);
I get an error saying this
IQueryable<SearchModel>' does not contain a definition for 'searchDomain'
and no accessible extension method 'searchDomain' accepting a first argument of type
'IQueryable<SearchModel>' could be found (are you missing a using directive or an assembly reference?)
This is my view model
public class SearchModel
{
public user searchUsers { get; set; }
public adminList searchAdmin { get; set; }
public domain searchDomain { get; set; }
}
Is there something I'm missing and/or is there a better way to implement the search?
I have a class in Entity framework 5 (using MVC 4):
public class JobFunction
{
public int Id { get; set; }
public string JobFunctionName { get; set; }
public int StatusId { get; set; }
public Status JFStatus { get; set; }
}
In my OnModelCreating method, I establish a FK relationship with the Status table as follows:
modelBuilder.Entity<JobFunction>().HasRequired(a => a.JFStatus).
WithMany().HasForeignKey(u => u.StatusId).WillCascadeOnDelete(false);
In my controller, I get a list of JobFunction objects as follows:
List<JobFunction> jfList = uow.JobFunctionRepository.GetAll().ToList<Catalog>();
where uow is my Unit of Work object, and JobFunctionRepository is defined. When I examine any JobFunction object in jfList, I see the following in my watch window:
Id: 1
JfStatus: null
JobFunctionName: "Manager"
StatusId: 2
Note that JFStatus is null. My question is: what provisions do I make in my code to initialize JFStatus to the appropriate Status object (based on the value of StatusId), during my GetAll call?
Thanks in advance.
-Zawar
You need some instrument to apply eager loading when you load the data through your repository. For example you could give your GetAll method a parameter list of expressions for the navigation properties you want to include in your query:
using System.Data.Entity;
//...
public IQueryable<JobFunction> GetAll(
params Expression<Func<JobFunction, object>>[] includes)
{
IQueryable<JobFunction> query = context.JobFunctions;
foreach (var include in includes)
query = query.Include(include);
return query;
}
Then you call it like so:
List<JobFunction> jfList = uow.JobFunctionRepository
.GetAll(jf => jf.JFStatus)
.ToList();
The JFStatus property should be filled now.
I have a CustomerOrder-view where I would like to change an existing CustomerOrder.
I have a viewmodel that very simpliefied looks something like this:
public class CustomerOrderViewModel
{
public int ID { get; set; }
public Customer Customer { get; set; }
public DateTime Date { get; set; }
public IEnumerable<OrderRow> OrderRows { get; set; }
}
public class OrderRow
{
public int id { get; set; }
public int price { get; set; }
}
public class Customer
{
public string Name { get; set; }
}
I also have a database with mapping tables / fields.
In my GET Action Method I load the Order with the help of Automapper like this:
var customerOrder = using (var ctx = new My_Entities()) {
return ctx.CustomerOrders.
Include("Orderrows").
Include("Customer").
Single(o => o.CustomerOrderID == id);
}
var model= AutoMapper.Mapper.DynamicMap<DataAccessLayer.CustomerOrder, CustomerOrderViewModel>(customerOrder);
In the View I use Knockout to bind to a viewmodel there, where the user can update the CustomerOrder. That includes editing Customer information and adding new orderrows etc.
Then in the post back a map the ViewModel back to the ObjectContext CustomerOrder:
var customerOrderToBeSaved =
AutoMapper.Mapper.DynamicMap<CustomerOrderViewModel, CustomerOrder>(
customerOrderViewModel);
try
{
using (var ctx = new MyEntities())
{
ctx.CustomerOrders.Attach(customerOrderToBeSaved);
ctx.CustomerOrders.ApplyCurrentValues(customerOrderToBeSaved);
...
ctx.SaveChanges();
}
}
I get the error message: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
OK, that I can understand. But how should I go about this? Can I get the existing object and apply Changes to that one, because that is really what I'd like. I've tried to look up the old one and detach it but I haven't got it to wrok.Perhaps I'm doing this in a completely wrong way. Please advice.
You should not attach customerOrderToBeSaved, see MSDN about the argument of ApplyCurrentValues.
The detached object that has property updates to apply to the original object.
So you've got to load the entity from the database into the context and then ApplyCurrentValues with the detached object that has the new values.
You don't have to load the row from the database to update it.
You can do something like this:
var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);
ctx.Entry( entity ).State = EntityState.Modified;
ctx.SaveChanges();
This will tell EF to issue an UPDATE SQL statement that overwrites all the columns in the record.
You can select which columns you want to update like this:
var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);
var entry = ctx.Entry( entity );
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
...
ctx.SaveChanges();
If you do this, EF will only include the columns you've marked as modified in the UPDATE statement.
Imagine a database table that looks like this:
create table [dbo].[user]
(
id int IDENTITY(1,1),
username varchar(50) NOT NULL,
firstname varchar(20) NOT NULL,
lastname varchar(30) NOT NULL,
currentid int NULL,
processedby varchar(50) NOT NULL,
processeddate varchar(50) NOT NULL
processedaction varchar(50) NOT NULL
)
What I want to do is to setup NHibernate to load it into my user object, but I only want the current version of the object "user" to be brought back. I know how to do a SQL select to do this on my own, and I feel as if there's something in nHibernate with the usage of triggers and event listeners, but can anyone tell me how to implement the nHibernate repository so I can:
{Repository}.GetCurrent(id) <- pass it any of the ids that are assigned to any of the historical or the current record, and get back the current object.
{Repository}.Save(user) <- I want to always insert the changes to a new row, and then update the old versions to link back to the new id.
Edit
So, there's some confusion here, and maybe I explained it wrong... What I'm trying to do is this, in regards to always getting the current record back...
Select uc.*
FROM User uo
JOIN User uc on uo.currentid=uc.id
WHERE uo.id==:id
But, I don't want to expose "CurrentID" to my object model, since it has no bearing on the rest of the system, IMHO. In the above SQL statement, uo is considered the "original" object set, and uc is considered the current object in the system.
Edit #2:
Looking at this as a possible solution.
http://ayende.com/blog/4196/append-only-models-with-nhibernate
I'm honestly being pigheaded, as I'm thinking about this backward. In this way of running a database, the autoincrementing field should be the version field, and the "id" field should be whatever the autoincrementer's value has at the time of the initial insert.
Answer:
I don't want to take #Firo's fury, and I'm not going to remove it from him, as he took me down the right path... what I wound up with was:
Created a base generic class with two types given
a. type of the object's "ID"
b. type of the object itself.
instantiate all classes.
create a generic interface IRepository class with a type of the object to store/retrieve.
create an abstract generic class with a type of the object to store/retrieve.
create a concrete implementation class for each type to store/retrieve.
inside of the create/update, the procedure looks like:
Type Commit(Type item)
{
var clone = item.DeepClone();
_Session.Evict(item);
clone.Id = 0;
clone.ProcessedDate = DateTime.Now;
if (clone.Action.HasValue)
{
if (clone.Action == ProcessedAction.Create)
clone.Action = ProcessedAction.Update;
}
else
{
clone.Action = ProcessedAction.Create;
}
clone.ProcessedBy = UserRepos.Where(u => u.Username == System.Threading.Thread.CurrentPrincipal.Identity.Name).First().Current;
var savedItem = (_Session.Merge(clone) as Type);
_Session.CreateQuery("UPDATE Type SET CurrentID = :newID where ID=:newID OR CurrentID=:oldID")
.SetParameter("newID", savedItem.Id)
.SetParameter("oldID", item.Id)
.ExecuteUpdate();
return savedItem;
}
In the delete method, we simply update the {object}.Action = ProcessedAction.Delete
I wanted to do this another way, but realizing we need to eventually do historical comparisons, we weren't able to ask nHibernate to filter the deleted objects, as the users will want to see that. We'll create a business facade to take care of the deleted records.
Again, much thanks to #Firo for his help with this.
So, with all that, I can finally do this:
var result = {Repository}.Where(obj => obj.Id == {objectID from caller}).FirstOrDefault();
if (result != null)
{
return result.Current;
}
else
{
return null;
}
and always get my current object back for any requesting ID. Hope it helps someone that is in my situation.
in mapping if you use FluentNHibernate
public UserMap : ClassMap<User>
{
public UserMap()
{
Where("id = currentid"); // always bring back the most recent
}
}
// in Userrepository
public void Update(User user)
{
var clone = user.Clone();
session.Evict(user); // to prevent flushing the changes
var newId = session.Save(clone);
session.CreateQuery("UPDATE User u SET u.currentid = :current") // <-- hql
.SetParameter("current", newId)
.ExecuteUpdate();
}
objectgraphs are a lot trickier with this simple code. I would then do one of the following:
use NHibernate.Envers to store auditing information for me
explicitly creating new entities in BL code
i once saw an append-only-model doing something like the following
// UserBase is there to ensure that all others referencing the User doesnt have to update because user properties changed
class UserBase
{
public virtual int Id { get; set; }
public virtual ICollection<PersonDetails> AllDetails { get; private set; }
public virtual PersonDetails CurrentDetails
{
get { return _currentDetauils; }
set { _currentDetauils = value; AllDetails.Add(value); }
}
// same as above
public virtual ICollection<ConfigDetails> AllConfigs { get; set; }
}
class Order
{
public virtual int Id { get; set; }
public virtual UserBase User { get; set; }
public virtual IList<OrderDetail> AllDetails { get; private set; }
public virtual IList<OrderDetail> ActiveDetails { get; private set; }
public virtual void Add(OrderDetail detail)
{
AllDetails.Add(detail);
ActiveDetails.Add(detail);
}
public virtual void Delete(OrderDetail detail)
{
detail.Active = false;
ActiveDetails.Remove(detail);
}
}
class OrderDetail
{
public virtual int Id { get; set; }
public virtual Order Parent { get; set; }
public virtual bool Active { get; set; }
}
class OrderMap : ClassMap<Order>
{
public OrderMap()
{
HasMany(o => o.AllDetails);
HasMany(o => o.ActiveDetails).Where("active=1");
}
}
// somewhere
public void UpdateTaxCharge(OrderDetail detail, TaxCharge charge)
{
var clone = detail.Clone();
clone.TaxCharge = charge;
detail.Order.Delete(detail);
detail.Order.Add(clone);
}
You can tell NHibernate what exactly SQL it should generate when persisting and loading an entity. For example you can tell NHibernate to use a stored procedure instead of a plain SQL statement. If this is an option for you I can farther elaborate my answer.
We have some old tables with legacy schemas that we find it hard to work with.
Is it possible to use NHibernate to transform some of this data into a nicer model?
For example we might have an integer status column that we want to break down into several properties.
Legacy status: 0 - Active, 1 - Inactive, 2 - TemporarilyInactive, 3 - etc
We'd want to have something like:
bool IsActive { get; set; }
Status Status { get; set; }
(where Status is an enum)
I know that we can use a protected field that can take the status and then define the getters for the extra properties to return the appropriate value based on the backing field, but I'm pretty sure that this will disable the ability to query based on these properties.
Through this however, we wouldn't be able to do queries such as .Query(p => p.IsActive) and get that translated to SQL such as where status = 0, right?
Is the only way through custom IUserTypes? If so, is there any helper framework that makes working with IUserType easier in order to achieve this?
How do other people handle this?
You can create your own "enumeration" class.
public class Status
{
//The numeric (legacy) code
public int Code{ get;private set; }
//The human readable name
public string Name{ get; private set; }
//If this status is an active status
public bool IsActive { get; private set; }
private Status(int aCode, string aName, bool anIsActive)
{
Code = aCode;
Name = aName;
IsActive = anIsActive;
}
public static Status ACTIVE = new Status(0, "Active");
public static Status INACTIVE = new Status(1, "Inactive");
//Other status here...
private static Status[] STATUSES = {Active,Inactive,...};
//Returns a status based on the passed in code
public static Status GetByCode(int aCode)
{
return STATUSES.FirstOrDefault(aStatus => aStatus.Code == aCode);
}
}
Then you can have NHibernate set a private variable with the legacy value and have a getter/setter that converts between the enumeration and the legacy value.
private int theLegacyStatus; //This is the value that NHibernate sets
public Status
{
get
{
return Status.GetStatusByCode(theLegacyStatus);
}
set
{
theLegacyStatus = value.Code;
}
}
You can then use this enumeration in NHibernate queries: .Query(p => p.Status.Code)