Returning distinct data for a dropdownlist box with selectlistItem - asp.net-mvc-4

I have a field in my database with duplicates. I want to use it in a dropdown list, which has to return distinct data.
Here is the method that I created to do this:
public IEnumerable<SelectListItem> GetBranches(string username)
{
using (var objData = new BranchEntities())
{
IEnumerable<SelectListItem> objdataresult = objData.ABC_USER.Select(c => new SelectListItem
{
Value = c.BRANCH_CODE.ToString(),
Text = c.BRANCH_CODE
}).Distinct(new Reuseablecomp.SelectListItemComparer());
return objdataresult;
}
}
Here is the class I am using:
public static class Reuseablecomp
{
public class SelectListItemComparer : IEqualityComparer<SelectListItem>
{
public bool Equals(SelectListItem x, SelectListItem y)
{
return x.Text == y.Text && x.Value == y.Value;
}
public int GetHashCode(SelectListItem item)
{
int hashText = item.Text == null ? 0 : item.Text.GetHashCode();
int hashValue = item.Value == null ? 0 : item.Value.GetHashCode();
return hashText ^ hashValue;
}
}
}
Nothing is returned and I get the error below. When I try a basic query without Distinct, everything works fine.
{"The operation cannot be completed because the DbContext has been disposed."}
System.Exception {System.InvalidOperationException}
Inner exception = null
How can I return distinct data for my dropdown?

Technically, your problem can be solved simply by appending .ToList() after your Distinct(...) call. The problem is that queries are evaluated JIT (just in time). In other words, until the actual data the query represents is needed, the query is not actually sent to the database. Calling ToList is one such thing that requires the actual data, and therefore will cause the query to be evaluated immediately.
However, the root cause of your problem is that you are doing this within a using statement. When the method exits, the query has not yet been evaluated, but you have now disposed of your context. Therefore, when it comes time to actually evaluate that query, there's no context to do it with and you get that exception. You should really never use a database context in conjuction with using. It's just a recipe for disaster. Your context should ideally be request-scoped and you should use dependency injection to feed it to whatever objects or methods need it.
Also, for what it's worth, you can simply move your Distinct call to before your Select and you won't need a custom IEqualityComparer any more. For example:
var objdataresult = objData.ABC_USER.Distinct().Select(c => new SelectListItem
{
Value = c.BRANCH_CODE.ToString(),
Text = c.BRANCH_CODE
});
Order of ops does matter here. Calling Distinct first includes it as part of the query to the database, but calling it after, as you're doing, runs it on the in-memory collection, once evaluated. The latter requires, then, custom logic to determine what constitutes distinct items in an IEnumerable<SelectListItem>, which is obviously not necessary for the database query version.

Related

How to get Phalcon to not reload the relation each time I want to access it

I am using Phalcon and have a model Order that has a one-to-many relationship with model OrderAddress. I access those addresses through the following function:
public function getAddresses($params = null) {
return $this->getRelated("addresses", array(
"conditions" => "[OrderAddress].active = 'Y'"
));
}
The OrderAddress model has a public property errors that I do not want persisted to the database. The problem I am having is that everytime I access the getAddresses function, it reloads the object from MySQL which completely wipes the values that I set against that property.
I really only want the OrderAddress models to be loaded once, so that each call to getAddresses doesn't make another trip to the DB- it just iterates over the collection that was already loaded.
Is this possible?
I suppose there's no such option in phalcon, so it has to be implemented in your code.
You could create an additional object property for cached addresses, and return it if it's already been initialized:
protected $cachedAddresses = null;
public function getAddresses($params = null) {
if ($this->cachedAddresses === null) {
$this->cachedAddresses = $this->getRelated("addresses", array(
"conditions" => "[OrderAddress].active = 'Y'"
));
}
return $this->cachedAddresses;
}
This could be a quick solution, but it will be painful to repeat it if you have other relations in your code. So to keep it DRY, you could redefine a 'getRelated' method in base model so it would try to return cached relations, if they already were initialized.
It may look like this:
protected $cachedRelations = [];
public function getRelated($name, $params = [], $useCache = true) {
//generate unique cache object id for current arguments,
//so different 'getRelated' calls will return different results, as expected
$cacheId = md5(serialize([$name, $params]));
if (isset($this->cachedRelations[$cacheId]) && $useCache)
return $this->cachedRelations[$cacheId];
else {
$this->cachedRelations[$cacheId] = parent::getRelated($name, $params);
return $this->cachedRelations[$cacheId];
}
}
Then, you can leave 'getAddresses' method as is, and it will perform only one database query. In case you need to update cached value, pass false as a third parameter.
And, this is completely untested, but even if there're any minor errors, the general logic should be clear.

Fluent subclasses - only first and last records are being cast into the correct types

I have a very strange issue that I cannot explain. I have my base mapping with this
//This will automatically cast the row into the correct object type based on the value in AccountType
DiscriminateSubClassesOnColumn<string>("AccountType")
.Formula(String.Format("CASE AccountType WHEN {0} THEN '{1}' WHEN {2} THEN '{3}' ELSE '{4}' END",
(int)PaymentMethodType.CheckingAccount,
typeof(ACH).Name,
(int)PaymentMethodType.SavingsAccount,
typeof(ACH).Name,
typeof(CreditCard).Name));
I have looked in the logs, I have executed the sql that nhibernate is generating, and all records have the same data. There is not difference in them that would denote why this should not work.
The base class is PaymentMethodBase. I have 2 subclasses, CreditCard and ACH, which inherit from PaymentMethodBase.
Then, I have this extension
public static string PaymentMethodName(this PaymentMethodBase paymentMethod)
{
if (paymentMethod is ACH)
{
var ach = (ACH)paymentMethod;
return String.Format("{0} {1}", ach.BankName, String.Format("XXXX{0}", ach.AccountNumber.Substring(ach.AccountNumber.Length - 4)));
}
if (paymentMethod is CreditCard)
{
var creditCard = (CreditCard)paymentMethod;
return String.Format("{0} {1}", creditCard.Name, creditCard.CreditCardNumber);
}
return "Unknown Payment Method";
}
Which I call like this.
public SelectList PaymentMethodsSelectList
{
get
{
var methods = (from p in PaymentMethods
where p != null
select new
{
id = p.PaymentMethodId,
name = p.PaymentMethodName()
}).OrderBy(x => x.name);
var results = methods.ToList();
results.Insert(0, new { id = (int)NewPaymentMethods.ACH, name = "<New eCheck Account...>" });
results.Insert(0, new { id = (int)NewPaymentMethods.CreditCard, name = "<New Credit Card...>" });
return new SelectList(results, "id", "name");
}
}
This code is used by 2 models. The collection of payment methods are all coming from the same object - a customer object. The collection is mapped like this.
HasMany<PaymentMethodBase>(x => x.PaymentMethods)
.KeyColumn("CustomerId")
.Where(y => y.AccountType < 10)
.Inverse()
.Cascade.All();
So, I get the customer 2 different ways. One is that I get the customer through another object (main site). The other has the object being pulled directly by id (in an iframe). The direct by id method works every time. The other method, where I get the customer through another object, causes only the first and last payment method to cast correctly. If there are more than 2, they are left in the base class and appear in the middle of the list after the sort.
I have tried changing the parent object to just mapping the id and then getting the customer record by the ID. Failure. There is something else in the way that is causing this to happen, but only on that one model.
I suspect that the issue here is Fetching issue.
Since the extension method is running on the .Net side rather than in the "NHibernate level" it cannot run properly when the collection of payment methods is not available.
Perhaps in the direct by Id methos you have Fetching set up for the payments whereas in the indirect method the automatic fetching goes only to the Customer object but stops short before fetching the Payment methods.
Try to instruct NHibernate to pre-fetch the Payment methods for you in the indirect method.
Something like:
Session.Query<SomeObject>.Where(.....).Fetch(x => x.Customer).ThenFetch(c => c.PaymentMethods)
The problem here appeared to be the usage of extension methods within a linq statement to return a value based on the type. The issue is that it would work some places but not others, probably due to some fetching issue, as suggested by Variant.
I solved this problem by making a property in my base class like this
public virtual string DisplayName { get { return "Unknown"; } }
Then I overrode the property in my child class and added the logic that was in the extension method for that type.
public override string DisplayName { get { return String.Format("{0} {1}", Name, AccountMask); } }

Why does this LINQ query assign a value of 1 to a NULL value from the database?

The ExamVersion class has an int? property named SourceSafeVersionNum
When I execute the following code:
var query = from examVersion in db.ExamVersions
where examVersion.ExamVersionID == ExamVersionID
select examVersion;
foreach (ExamVersion examVer in query.ToList())
{
yield return examVer;
}
examVer.SourceSafeVersionNum is set to 1 even though it is NULL in the database.
When I run the SQL code generated by LINQ in SQL Server, the SourceSafeVersionNum column value is NULL (as I'd expect) but in the foreach loop the examVer.SourceSafeVersionNum is 1.
I can't find anywhere in the code where a default value is assigned or any similar logic.
Any ideas why/where this value is being set to 1?
Here is the property declaration (generated by a .dbml file)
[Column(Storage="_SourceSafeVersionNum", DbType="Int", UpdateCheck=UpdateCheck.Never)]
public System.Nullable<int> SourceSafeVersionNum
{
get
{
return this._SourceSafeVersionNum;
}
set
{
if ((this._SourceSafeVersionNum != value))
{
this.OnSourceSafeVersionNumChanging(value);
this.SendPropertyChanging();
this._SourceSafeVersionNum = value;
this.SendPropertyChanged("SourceSafeVersionNum");
this.OnSourceSafeVersionNumChanged();
}
}
}
Have you tried setting a breakpoint in the set{} method of the property to see what else might be populating its value? You might catch the culprit in the act, then look at the Call Stack to see who it is.
As a follow up to this, here is what happened:
The code that retrieved the value from the database was being called twice but through two different code paths. The code path that was assigning the value of 1 was being stepped over by the debugger so I didn't see it.

How to work around NHibernate caching?

I'm new to NHibernate and was assigned to a task where I have to change a value of an entity property and then compare if this new value (cached) is different from the actual value stored on the DB. However, every attempt to retrieve this value from the DB resulted in the cached value. As I said, I'm new to NHibernate, maybe this is something easy to do and obviously could be done with plain ADO.NET, but the client demands that we use NHibernate for every access to the DB. In order to make things clearer, those were my "successful" attempts (ie, no errors):
1
DetachedCriteria criteria = DetachedCriteria.For<User>()
.SetProjection(Projections.Distinct(Projections.Property(UserField.JobLoad)))
.Add(Expression.Eq(UserField.Id, userid));
return GetByDetachedCriteria(criteria)[0].Id; //this is the value I want
2
var JobLoadId = DetachedCriteria.For<User>()
.SetProjection(Projections.Distinct(Projections.Property(UserField.JobLoad)))
.Add(Expression.Eq(UserField.Id, userid));
ICriteria criteria = JobLoadId.GetExecutableCriteria(NHibernateSession);
var ids = criteria.List();
return ((JobLoad)ids[0]).Id;
Hope I made myself clear, sometimes is hard to explain a problem when even you don't quite understand the underlying framework.
Edit: Of course, this is a method body.
Edit 2: I found out that it doesn't work properly for the method call is inside a transaction context. If I remove the transaction, it works fine, but I need it to be in this context.
I do that opening a new stateless session for geting the actual object in the database:
User databaseuser;
using (IStatelessSession session = SessionFactory.OpenStatelessSession())
{
databaseuser = db.get<User>("id");
}
//do your checks
Within a session, NHibernate will return the same object from its Level-1 Cache (aka Identity Map). If you need to see the current value in the database, you can open a new session and load the object in that session.
I would do it like this:
public class MyObject : Entity
{
private readonly string myField;
public string MyProperty
{
get { return myField; }
set
{
if (value != myField)
{
myField = value;
DoWhateverYouNeedToDoWhenItIsChanged();
}
}
}
}
googles nhforge
http://nhibernate.info/doc/howto/various/finding-dirty-properties-in-nhibernate.html
This may be able to help you.

LINQ SQL Attach, Update Check set to Never, but still Concurrency conflicts

In the dbml designer I've set Update Check to Never on all properties. But i still get an exception when doing Attach: "An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported." This approach seems to have worked for others on here, but there must be something I've missed.
using(TheDataContext dc = new TheDataContext())
{
test = dc.Members.FirstOrDefault(m => m.fltId == 1);
}
test.Name = "test2";
using(TheDataContext dc = new TheDataContext())
{
dc.Members.Attach(test, true);
dc.SubmitChanges();
}
The error message says exactly what is going wrong: You are trying to attach an object that has been loaded from another DataContext, in your case from another instance of the DataContext. Dont dispose your DataContext (at the end of the using statement it gets disposed) before you change values and submit the changes. This should work (all in one using statement). I just saw you want to attach the object again to the members collection, but it is already in there. No need to do that, this should work just as well:
using(TheDataContext dc = new TheDataContext())
{
var test = dc.Members.FirstOrDefault(m => m.fltId == 1);
test.Name = "test2";
dc.SubmitChanges();
}
Just change the value and submit the changes.
Latest Update:
(Removed all previous 3 updates)
My previous solution (removed it again from this post), found here is dangerous. I just read this on a MSDN article:
"Only call the Attach methods on new
or deserialized entities. The only way
for an entity to be detached from its
original data context is for it to be
serialized. If you try to attach an
undetached entity to a new data
context, and that entity still has
deferred loaders from its previous
data context, LINQ to SQL will thrown
an exception. An entity with deferred
loaders from two different data
contexts could cause unwanted results
when you perform insert, update, and
delete operations on that entity. For
more information about deferred
loaders, see Deferred versus Immediate
Loading (LINQ to SQL)."
Use this instead:
// Get the object the first time by some id
using(TheDataContext dc = new TheDataContext())
{
test = dc.Members.FirstOrDefault(m => m.fltId == 1);
}
// Somewhere else in the program
test.Name = "test2";
// Again somewhere else
using(TheDataContext dc = new TheDataContext())
{
// Get the db row with the id of the 'test' object
Member modifiedMember = new Member()
{
Id = test.Id,
Name = test.Name,
Field2 = test.Field2,
Field3 = test.Field3,
Field4 = test.Field4
};
dc.Members.Attach(modifiedMember, true);
dc.SubmitChanges();
}
After having copied the object, all references are detached, and all event handlers (deferred loading from db) are not connected to the new object. Just the value fields are copied to the new object, that can now be savely attached to the members table. Additionally you do not have to query the db for a second time with this solution.
It is possible to attach entities from another datacontext.
The only thing that needs to be added to code in the first post is this:
dc.DeferredLoadingEnabled = false
But this is a drawback since deferred loading is very useful. I read somewhere on this page that another solution would be to set the Update Check on all properties to Never. This text says the same: http://complexitykills.blogspot.com/2008/03/disconnected-linq-to-sql-tips-part-1.html
But I can't get it to work even after setting the Update Check to Never.
This is a function in my Repository class which I use to update entities
protected void Attach(TEntity entity)
{
try
{
_dataContext.GetTable<TEntity>().Attach(entity);
_dataContext.Refresh(RefreshMode.KeepCurrentValues, entity);
}
catch (DuplicateKeyException ex) //Data context knows about this entity so just update values
{
_dataContext.Refresh(RefreshMode.KeepCurrentValues, entity);
}
}
Where TEntity is your DB Class and depending on you setup you might just want to do
_dataContext.Attach(entity);