Nhibernate equal restriction on guid - c#

I have a class, Comapny, with userId as system.Guid, i want to filter that company (userId is not the primary key), but when I do it like this:
List<Company> list =
session.CreateCriteria<Company>().Add(Restrictions.Eq("UserId", userId))
.List<Company>().ToList();
The list is returning empty even though there are rows in the db with that property.
I tried doing it like this:
Company companyResult = null;
list.ForEach(delegate (Company company)
{
if (company.UserId.Equals(userId))
{
if (companyResult == null)
{
companyResult = company;
}
}
});
return companyResult;
and it works, is there a reason why Nhibernate eq won't work on this Guid?

Why not using the Query method?
var list = session.Query<Company>().Where(x => x.UserId == userId).ToList();

The best you can do to really investigate this, is to switch on show-sql, apparently you are retrieving something different from the database then you think?

Related

Copy the duplicate records in MVC using Entity Framwork

I am new in MVC Entity Framework.
I have one Table called Product. it contain 40 fields.
I have one task to copy the Product or to create the duplicate record in same table with new Product ID..
How can I do this in efficient ways?
I tried using the below code
Public ActionResult CopyProduct(long ProductID)
{
var oldProductScript = db.Products.FirstOrDefault(x=>x.ProductID == ProductID)
Product p = new Product();
p.name = oldProductScript.name;
p.price =oldProductScript.price;
p.model =oldProductScript.model;
p.image = oldProductScript.image;
p.status =oldProductScript.status;
.
.
.
.
.
like so till 40th field
db.Products.AddObject(p);
db.SaveChanges();
}
Is this the proper way to complete this task?
Please suggest.
Thanks
If you want this to be done much easier(reduced coding), I would recommend you to use Code First Approach.
Use this link to know what is it and code sample.
After you add the tables with models(DBContext) as using Code First Approach, you would be able to easily get and set properties of the table even faster than your usual method.
public class InheritanceMappingContext : DbContext
{
public DbSet<TableName> TableProperty { get; set; }
}
Use a polymorphic query to retrieve the fields of the table.
IQueryable<TableName> linqQuery = from b in context.TableName select b;
List<TableName> tableFields = linqQuery.ToList();
linqQuery returns list of objects of the type
Warning: I've tested this with one of my classes and it worked. Not sure if it will work with yours:
var prod = context.Products.FirstOrDefault(p => p.ProductID == ProductID);
var prod2 = new Products();
foreach (PropertyInfo pi in prod.GetType().GetProperties())
{
prod2.GetType().GetProperties().First(p=>p.Name==pi.Name).SetValue(prod2, pi.GetValue(prod, null), null);
}
//prod2 is now a clone of prod. Make sure to adjust your product ID before adding the new product.
Try something like this:
Products productToCopy = db.Products.FirstOrDefault(p => p.ProductId == productID);
db.Entry(productToCopy).State = EntityState.Detached;
productToCopy.ProductId = 0;
db.Products.Add(productToCopy);
db.SaveChanges();

Linq help - sub query gives null pointer exception

I writing a email system where we have a table of users "tblUsers" and a table of messages. A user can have many messages (from other users in tblusers) in his or her inbox (one:many).
In tblUsers table, I have a column called ImageURL (string) that contains the URL to the user's avatar. In this case, I'm looping through the messages in an inbox belonging to a user and what I'm trying to do is, once I get the message, walk up the tree to the tblUser and get the value in the ImageURL column for the owner of that message as marked "SenderAvatar" below.
Here's what I tried. The problem is that the sub linq for SenderAvatar below is throwing a nullpointer exception even though I have confirmed that there is a value for ImageURL (this is dev so there's only three users). Somehow my logic and linq's logic is at odds here. Can someone please help? Thanks!
Edit
I found two bugs. The first bug is Dzienny pointed me to the right direction where I was comparing apples and oranges. The second bug is FromUserId = ux.tblUserId, where I'm setting the current user id to FromUserId Guys, thank you for all your help on this.
public List<UserInboxMsg> GetUserInboxMsg(IKASLWSEntities conx, int userid)
{
var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();
if (u != null)
{
return (from ux in u.tblInboxes
orderby ux.CreationTS descending
select new UserInboxMsg
{
CreationTS = ux.CreationTS,
ExpirationDate = ux.ExpirationDate,
FromUserId = ux.tblUserId,
HasImage = ux.HasImage,
ImageId = ux.ImageId ?? 0,
IsDeleted = ux.IsDeleted,
IsRead = ux.IsRead,
MsgId = ux.Id,
MsgSize = ux.MessageSize,
ParentId = ux.ParentId,
Title = ux.Title,
ToUserId = userid,
FromUserName = ux.Title,
SenderAvatar = conx.tblMessages.Where(mu=>mu.Id == ux.Id).FirstOrDefault().tblUser.ImageURL,
Message = ux.Message
}).ToList<UserInboxMsg>();
}
else
{
return new List<UserInboxMsg>();
}
}
}
If in the entity-framework, there is a foreign key reference between the two tables you could probably do this:
SenderAvatar = conx.tblMessages.FirstOrDefault( mu=>mu.Id == ux.Id).ImageURL,
Try this.
public List<UserInboxMsg> GetUserInboxMsg(IKASLWSEntities conx, int userid)
{
var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();
if (u != null && conx != null)
{
return (from ux in u.tblInboxes
orderby ux.CreationTS descending
select new UserInboxMsg
{
...
...
SenderAvatar = conx.tblMessages.Any(mu=>mu.Id == ux.Id) ? (conx.tblMessages.First(mu=>mu.Id == ux.Id).tblUser != null? conx.tblMessages.First(mu=>mu.Id == ux.Id).tblUser.ImageURL : null) : null,
Message = ux.Message
}).ToList<UserInboxMsg>();
}
else
{
return new List<UserInboxMsg>();
}
}
}
if you are getting null for the Avatar, it is either because there are no entries in tblMessages where mu.Id equals ux.Id or the tblMessage entry is there but the tblUser property is null
There are several problems here.
The first is that the second statement is executed in memory, while it's possible to make the whole query run as SQL:
from u in conx.tblUsers where m.Id == userid
from ux in u.tblInboxes
orderby ux.CreationTS descending
select new UserInboxMsg
{
CreationTS = ux.CreationTS,
ExpirationDate = ux.ExpirationDate,
FromUserId = ux.tblUserId,
HasImage = ux.HasImage,
ImageId = ux.ImageId ?? 0,
IsDeleted = ux.IsDeleted,
IsRead = ux.IsRead,
MsgId = ux.Id,
MsgSize = ux.MessageSize,
ParentId = ux.ParentId,
Title = ux.Title,
ToUserId = userid,
FromUserName = ux.Title,
SenderAvatar = conx.tblMessages.Where(mu => mu.Id == ux.Id)
.FirstOrDefault().tblUser.ImageURL,
Message = ux.Message
}
This has three benefits:
you fetch less data from the database
you get rid of the null reference exception, because SQL doesn't have null references. It just returns null if a record isn't found.
you can return the result of this statement without the if-else.
Second, less important, is that you should use a navigation property like Inbox.Messages in stead of joining (sort of) the inbox and its messages. This makes it less likely that you use the wrong join variables and it condenses your code:
SenderAvatar = ux.Messages.
.FirstOrDefault().User.ImageURL,
Now if there is no avatar, there is no avatar. And there's no null reference exception.
(By the way, you can see that I hate these prefixes in class and property names).
I can only guess this part of your code is wrong : SenderAvatar = conx.tblMessages.Where(mu=>mu.Id == ux.Id).FirstOrDefault().tblUser.ImageURL
I think for example you should use (mu=>mu.UserId == ux.Id) instead of (mu=>mu.Id == ux.Id). In your code, you are comparing "Id" of a table to "Id" of another table which normally in one to many relations is wrong. (only works in one to one relations)
I said I can guess because you didn't mention any information about tblInboxes and tblMessages fields. If you could provide me more information about their structure, I could answer in more detail.
By the way to make your code more clear you can use:
var u = conx.tblUsers.FirstOrDefault(m=>m.Id == userid);
instead of
var u = (from m in conx.tblUsers where m.Id == userid select m).FirstOrDefault();
OR
conx.tblMessages.FirstOrDefault(mu=>mu.Id == ux.Id)
instead of
conx.tblMessages.Where(mu=>mu.Id == ux.Id).FirstOrDefault()

is this EF6 code supposed to have queries in it?

I'm trying to understand how to use Entity Framework 6. The code below works. However, it appears to have four queries in it for a single write operation. It doesn't seem right to hit the database five separate times. I want a single database call that adds the appropriate item to each table as needed. Is there some better way to do the code below? Or is it really doing a single database hit in the SaveChanges call?
public bool Write(ILogEntry logEntry)
{
var log = logEntry as AssetStateLogEntry;
if (log == null) return false;
using (var db = _dbContextProvider.ConstructContext())
{
if (db != null)
{
var state = new VehicleStateLogEntryDbo
{
LogSource = db.LogSources.FirstOrDefault(l => l.Name == log.Source.ToString())
?? new LogSourceDbo {Name = log.Source.ToString()},
Message = log.Message,
TimeStamp = log.TimeStamp.ToUniversalTime(),
Vehicle = db.Vehicles.FirstOrDefault(v => v.Name == log.Asset.Name)
?? new VehicleDbo {Name = log.Asset.Name, VehicleIdentifier = log.Asset.ID},
VehicleState = db.VehicleStates.FirstOrDefault(v => v.Name == log.StateValue.ToString() && v.VehicleStateType.Name == log.StateType.ToString())
?? new VehicleStateDbo
{
Name = log.StateValue.ToString(),
VehicleStateType = db.VehicleStateCategories.FirstOrDefault(c => c.Name == log.StateType.ToString())
?? new VehicleStateTypeDbo {Name = log.StateType.ToString()},
}
};
db.VehicleStateLogEntrys.Add(state);
db.SaveChanges();
}
}
return true;
}
You are indeed making 4 queries to the database, as a result of these calls:
db.LogSources.FirstOrDefault
db.Vehicles.FirstOrDefault
db.VehicleStates.FirstOrDefault
db.VehicleStateCategories.FirstOrDefault
When you call FirstOrDefault, the LINQ query is executed and thus, the database is hit.
I don't know your schema, but maybe you could join some of them into a single LINQ query (at least the Vehicles* tables seem to be related).
EDIT: sample query using joins as requested by the OP
Take the following query as an starting point of what I suggested, you haven't provided your entities so this is just to give you and idea:
from l in db.LogSources
join v in db.Vehicles on l.Asset.ID equals v.VehicleIdentifier
join vs in db.VehicleStates on vs.VehicleIdentifier equals v.VehicleIdentifier
where l.Name == log.Source.ToString()
&& v.Name == log.Asset.Name
&& vs.Name == log.StateValue.ToString()
&& vs.VehicleStateType.Name == log.StateType.ToString()
select new VehicleStateLogEntryDbo
{
LogSource = l,
Message = log.Message,
TimeStamp = log.TimeStamp.ToUniversalTime(),
Vehicle = s,
VehicleState = vs
}
A couple considerations:
As #Gert suggested, you should probably use foreign keys instead of whole object references.
I haven't considered the possibilities of null values in the example, you can take them into account using left joins with DefaultIfEmpty.
In stead of setting object references you should set primitive foreign key values. From an object-oriented point of view this sounds like a heresy, but it's Entity Framework's recommended approach when it comes to setting associations efficiently.
Of course, there should be foreign key values to be set in the first place. In your VehicleStateLogEntryDbo this could look like:
public int VehicleIdentifier { get; set; } // or guid?
[ForeignKey("VehicleIdentifier")]
public VehicleDbo Vehicle { get; set }
The ForeignKey attribute tells EF that both properties belong together in a foreign key association. This can also be configured by the fluent API, e.g. in the OnModelCreating override:
modelbuilder.Entry<VehicleStateLogEntryDbo>()
.HasRequired(v => v.Vehicle)
.WithMany()
.HasForeignKey(v => v.VehicleIdentifier);
By the way, having a Vehicle property only is referred to as an independent association.
So when you have these foreign key associations in place you can simply set the FK values. Maybe you should modify your DTO to transfer these values in stead of names etc.

how to convert IQueryable<Category> to Category

I have a database with 2 tables: "Albumes" and "Categories".
Each Album has an "id" and a "categoryId" property. although each Category has a "name" property.
I can get the Album.id via QueryString from another page and show the desired Album details in a formview. now i want to show the name of category which contains that album.
I try to do this:
public string GetCategoryName(int albumCategoryId)
{
var _db = new Trying.Models.AlbumContext();
IQueryable<Category> query = _db.Categories;
query = query.Where(c => c.id == albumCategoryId);
Category ca = new Category();
//some code
return ca.name;
}
My problem is in "//some code" section! there, I must convert "IQueryabl query" to "Category ca".
How to do this?
Where returns a set of all matching entities but you only want a single one.
public string GetCategoryName(Int32 albumCategoryId)
{
using (var _db = new Trying.Models.AlbumContext())
{
return _db.Categories.Single(c.id == albumCategoryId).Name;
}
}
Using Single will throw an exception if there is no matching category and you should use this if you are sure that the category has to exist. If you are not sure whether the category exists or not, you can use SingleOrDefault to get null if there is no matching category. First or FirstOrDefault would work, too, but they are semantically wrong because you don't want the first category, you want to only one. SingleOrDefault obviously requires handling the case that there is no matching category.
public string GetCategoryName(Int32 albumCategoryId)
{
using (var _db = new Trying.Models.AlbumContext())
{
var category = _db.Categories.SingleOrDefault(c.id == albumCategoryId);
if (category != null)
{
return category.Name;
}
else
{
// Handle the no category found case by returning a default value,
// throwing an exception or what ever fits your needs.
}
}
}
Also note that you should use your database context in an usingstatement to ensure that it gets early and correctly disposed even in the case of an error.
Further you can access the name of the category directly by navigating through your navigation properties.
var categoryName = album.Category.Name;
This is obviously only useful when you have the album object available and you have to ensure that you load the category by either using lazy loading or explicitly including it if you use eager loading.
var album = _db.Albumes.Include(a => a.Category)
.Single(a => a.Id = 42);
This will load the album with Id 42 and because of Include(a => a.Category) also the category of this album. Whether this is better or worse than explicitly querying the category name depends of course on your requirements.
Try this:
public string GetCategoryName(int albumCategoryId)
{
var _db = new Trying.Models.AlbumContext();
IQueryable<Category> query = _db.Categories;
Category ca = query.First(c => c.id == albumCategoryId);
return ca.name;
}
I will explain with some examples, check the type of the variable because thats what each line is going to return:
list<Category> list = query.Where(c => c.id == albumCategoryId).AsEnumerable();
Category category= query.FisrtOrDefault(c => c.id == albumCategoryId);
IQueryable<T> is a collection.
You need to limit your collection to a single item.
query.Where will also result in a collection. I believe you're looking for a unique item by id. I would recommend Single instead:
var ca = query.Single(c => c.id == albumCategoryId);
return ca.name;

Using .Contains() on a property in a list

I have a List of Activity. In the Activity class is an ID property (a Guid for arguments sake). I want to check if this list has an Activity in it with a Guid I have. Rather than this:
foreach(Activity activity in ActivityList)
{
if(activity.Id == GuidToCompare)
//Code here
}
Is there a more efficient way to achieve the same result as I could if I were to have just a list of Guids (instead of a list of Activity's) and to use .Contains()?
I've got a list of a struct called ActivityAndPO. In this struct is a Guid.
I have a list of PO's. In the PO class is a Guid.
I want to loop through all of objects in the the ActivityAndPO list where the Guid's exist in the list of PO's.
Sure.
foreach(Activity activity in ActivityList.Where(a => a.Id == GuidToCompare) )
{
//Code here
}
But since Id implies there will be at most 1 activity:
//var act = ActivityList.Where(a => a.Id == GuidToCompare).SingleOrDefault(); // clearer
var act = ActivityList.SingleOrDefault(a => a.Id == GuidToCompare); // shorter
if (act != null)
{
//Code here
}
Take a look to the LINQ, You can replace with it your code by: ActivityList.Any(i => i.Id == GuidToCompare);
foreach(var activity in ActivityList.Where(p=>p.Id == GuidToCompare))
{
// Code here
}
to find all activity objects with the given GUID you can use:
var results = ActivityList.FindAll(item => item.ID == GuidToCompare);
If you are looking for only one Id one time, there is no more efficient way.
If you are looking for Ids multiple times you can build a HashSet :
var activityIdsQuery = from a in ActivityList
select a.Id;
HashSet<Guid> activityIds = new HashSet<Guid>(activityIdsQuery);
//Use the hashset
activityIds.Contains(id);
If you need to find an instance of activity you can build a Dictionary (works only if Id is unique) :
Dictionary<Guid, Activity> activities = ActivityList.ToDictionary(a => a.Id);
Others solution using Linq with Where/FirstOrDefault/Any on the Id won't be more efficient than yours.
I Havent tested it but im fairly sure this should work:
if ( ActivityList.Any ( a => a.Id == GuidToCompare ) ) {
// TODO - Exists.
}
MSDN Any : http://msdn.microsoft.com/en-us/library/bb534972.aspx
Just to offer you all the ways you can write this query with Linq
var result = (from activity in activityList
where activity.Id == GuidToCompare
select activity ).FirstOrDefault();
if(result != null)
/* Code here */
Now, it is up to you to choose the more readable snippet ;)
For those who can't use LINQ:
List<Activity> ActivityList = new List<Activity>();
foreach (Activity activity in ActivityList.FindAll(delegate(Activity a)
{
return a.Id == GuidToCompare;
}))
{
//Code here
}

Categories

Resources