I have these two methods on a service:
public Offer GetOffer(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Offer offerEntity = _db.Offers.FirstOrDefault(offer => offer.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using (IDocumentSession session = store.OpenSession())
{
Translation.Offer translatedOffer = session.LuceneQuery<Translation.Offer>(Website.RavenDbSettings.Indexes.Offers)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(offer => offer.Id)
.FirstOrDefault();
var offerPOCO = Mapper.DynamicMap<Translation.Offer, Offer>(translatedOffer);
offerPOCO.Id = offerEntity.Id;
return offerPOCO;
}
}
return Mapper.Map<Entities.Offer, Offer>(offerEntity);
}
And
public Hotel GetHotel(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Hotel hotelEntity = _db.Hotels.FirstOrDefault(hotel => hotel.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation.Hotel translatedHotel = session.LuceneQuery<Translation.Hotel>(Website.RavenDbSettings.Indexes.Hotels)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(hotel => hotel.Id)
.FirstOrDefault();
Hotel hotelPOCO = Mapper.DynamicMap<Translation.Hotel, Hotel>(translatedHotel);
hotelPOCO.Id = hotelEntity.Id;
return hotelPOCO;
}
}
return Mapper.Map<Entities.Hotel, Hotel>(hotelEntity);
}
They are exactly the same in most aspects: they take the same params, build the same query and make the same operations, the only thing that varies is the type of objects they work with and output. Besides building a method to generate the Where() param string, I can't think of any way I can merge most (or all) of this code into a single method and then just call it from the GetOffer() and GetHotel() methods since I'll end up with several more just like these two.
Any advice is greatly appreciated.
Edit: adding the solution so if another poor soul comes across this problem he/she can have a starting point:
private TReturn GetObject<TReturn, TEntity, TTranslation>(int id, string languageCode, string ravenDbIndex) where TEntity:EntityObject
where TTranslation:Translation.BaseTranslationObject
where TReturn:BasePOCO
{
// TODO Run more tests through the profiler
var entities = _db.CreateObjectSet<TEntity>();
var entityKey = new EntityKey(_db.DefaultContainerName + "." + entities.EntitySet.Name, "Id", id); // Sticking to the Id convention for the primary key
TEntity entity = (TEntity)_db.GetObjectByKey(entityKey);
if(languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
TTranslation translatedObject = session.LuceneQuery<TTranslation>(ravenDbIndex)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(translation => translation.Id)
.FirstOrDefault();
TReturn poco = Mapper.DynamicMap<TTranslation, TReturn>(translatedObject);
poco.Id = id;
return poco;
}
}
return Mapper.Map<TEntity, TReturn>(entity);
}
And then I just call:
GetObject<Hotel, Entities.Hotel, Translation.Hotel>(id, languageCode, Website.RavenDbSettings.Indexes.Hotels);
Whenever I need a hotel.
Thank you all for the great replies, learned quite a lot from them.
It looks as though you could refactor this into a generic method. Something similar to this (I'm making some assumptions about the ability to refactor some method calls, etc. But hopefully you get the idea)
public T Get<T>(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entity<T> entity = _db<T>.FirstOrDefault(entity => entity.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation<T> translatedEntity = session.LuceneQuery<Translation<T>>(Website.RavenDbSettings.Indexes.Entities<T>)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(entity=> entity.Id)
.FirstOrDefault();
T POCO = Mapper.DynamicMap<Translation<T>, T>(translatedEntity);
POCO.Id = entity.Id;
return POCO;
}
}
return Mapper.Map<Entities<T>, T>(Entity);
}
Suggest keeping them as-is. They return different types, and warrant different methods. My gut feeling is that it falls under Do One Thing - Single Responsibility Principle.
True that they implement the same strategies in doing their work, but I'd suggest that if you were to merge/refactor them into one would be more confusing than benefiting.
Consider the likelihood of the business logic changing. Would one be more volatile than the other? Would implementing this be same as GetFlights() and GetCarRentals()?
I realize that when making code the same, and likely copy/pasting/tweaking code between methods, you get the sense that you could reduce lines of code, and don't repeat yourself. I value both SRP and DRY equally, but in this case, I'd rather read and maintain different methods for each entity of Offer, Hotel, etc.
In cases like this I isolate the variable terms and put them in the sig, if the sig turns out too large and difficult/ugly to call then see if generics can make this simpler or if parts can be factored into their types which is what I would think to do in this case. Also having an action or a func in the sig can help if it would never be difficult to fill in at call, something where you could maybe call:
GetDalObject(db => db.Hotels.FirstOrDefault(hotel => hotel.Id == id), ...
Then you can swap it in the call between hotel or offer or etc, but in your case I don't know how much this can help since I think the sig would really become nasty, so I would look at taking the variable parts and implementing them in the Offer type and the Hotel type, which you access via an interface, and then the Offer/Hotel class is handed to this method.
public interface ICommonDalObject
{
public string LuceneQueryString { get; }
public ITranslation GetTranslation();
}
Related
If it okay to use foreach for a simple query like this? Or should I always use the query thing ?
public static Staff GetTeacher(Context context, int staffId)
{
foreach (Staff staff in context.Staff)
{
if(staff.StaffID == staffId)
{
return staff;
}
}
return null;
}
public static object GetTeacher(Context context, int staffId)
{
var staff = from teacher in context.Staff
where teacher.StaffID == staffId
select new
{
Id = teacher.StaffID,
Teacher = teacher.FirstName + " " + teacher.LastName
};
return staff;
}
The foreach will loop over every record in your database table until it finds a match, meaning it might eventually pull every single record into memory. That could be incredibly slow.
The Linq query will construct an SQL statement that only pulls out the relevant record(s).
So the second option is far better. However, it looks like you tried to fix the fact your second query give an enumerable list of staff object by making the function return an object. Instead, you can make the entire thing look much nicer, something like this:
public static Staff GetTeacher(Context context, int staffId)
{
return context.Staff.Single(s => s.StaffID == staffId);
}
This will be the most efficient method. It will throw an exception if there is no matching staffId in the database. That might be a good thing for you. If not, change it to use SingleOrDefault instead of Single.
Side note: I'm concerned about the method being static. This suggests the DbContext might be shared or long-lived which are both bad things.
IEnumerable<IGrouping<StatusType, Request>> group = requests.GroupBy(r=> r.StatusType );
The grouping function above works with when requests (List<Requests>) is from EntityFramework/db.
When changing the assignment of requests from db direct, to a web service,
the grouping isn't working as intended.
Digging a bit, I found that the hash or equality of the StatusType's is different when coming from db vs web (found out thru this post).
From the accepted answer of the post, I can bypass/(resolve?) the problem by overriding..
public class StatusType : IEquatable<int>
{ // omitted other crucial equality comparison components.
// but for brevity..
public override int GetHashCode()
{
return Id;
}
}
Although overriding StatusType somewhat resolves the issue,
I feel its quite risky as
I am not the author of the code base.
There are multiple references to StatusType increasing the potential
of impending failure.
My question,
Is there a way to group by the StatusTypeId (int)
requests.groupBy(r=> r.StatusTypeId) // returns IEnumerable<IGrouping<int,Rquest>>
but get the StatusType?
IEnumerable<IGrouping<StatusType,Rquest>>
Define comparer for StatusType:
public class StatusTypeComparer : IEqualityComparer<StatusType>
{
public bool Equals(StatusType x, StatusType y)
{
return x.Id == y.Id;
}
public int GetHashCode(StatusType obj)
{
return obj.Id.GetHashCode();
}
}
Pass it to GroupBy method:
IEnumerable<IGrouping<StatusType, Request>> group =
requests.GroupBy(r => r.StatusType,
new StatusTypeComparer());
Disclaimer: Backs has a much better answer than mine but I thought I'd post it anyway in the interests of diversity.
You might be able to get something like the functionality you're looking for by using multiple Linq queries. I don't know if there is an accessible implementation of IGrouping I can use, so I've gone with Tuple<StatusType, List<Request>> instead. It should have a similar effect. So, from your original query:
IEnumerable<IGrouping<int, Request>> group = requests.GroupBy(r=> r.StatusTypeId );
You can add the following line:
IEnumerable<Tuple<StatusType, List<Request>>> groupByStatusType =
group.Select(x => new Tuple<StatusType, List<Request>>(x.First().StatusType,
x.ToList()));
Or, you can do it all on one line:
IEnumerable<Tuple<StatusType, List<Request>>> group =
requests.GroupBy(r => r.StatusTypeId)
.Select(x => new Tuple<StatusType, List<Request>>(x.First().StatusType,
x.ToList()));
You can of course tweak the queries depending on what kind of output you're expecting, but this should at least get you started. Alternately, you could get a similar result by implementing a function that iterates through everything and "manually" creates an output.
Is there any way to return a string parameter and a list to the method in c#?
List<cCountry> countries = new List<cCountry>();
countries = GetCountries(userProfile.Country);
private List<cCountry> GetCountries(string p)
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
outputCollection = UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
List<cCountry> countries = new List<cCountry>();
cDTOSingleValue SelectedCountryID = new cDTOSingleValue();
foreach (cDTOCountry countryItem in outputCollection)
{
if (p == countryItem.CountryName)
SelectedCountryID.Id = countryItem.CountryID;
countries.Add(Mapper.Map<cDTOCountry, cCountry>(countryItem));
}
countries.Remove(countries[0]);
return countries;
}
Like in the method above I need to return a parameter
SelectedCountryID and also the countries list.Is there any way to
return both?
populate and return an object instead.
public class ReturnObject
{
public List<cCountry> Countries { get; set; }
public guid SelectedCountryID { get; set; } // don't think you defined what type SelectedCountryID is in your question
}
But if you find yourself needing to return more than 1 thing, it's probably an indication that your method is doing too much and should be refactored.
Why can't you reuse the value that you are sending to the method?
return Tuple.Create(new List<Country>(),"astring")
Answer to your question
You can also use the out modifier on a parameter to pass by reference, which would let the method modify the resulting object, effectively returning it. That's a pretty bad design for most cases though, and you probably refactor your methods into smaller pieces or wrap things up into better objects.
In your code:
private List<cCountry> GetCountries(string p, out cDTOSingleValue SelectedCountryID)
{
//your code
}
Potential Refactoring
Looking at your code it, seems your really are trying to do two separate things.
Getting Countries and mapping them
Finding the last country whose name matches the parameter passed in
So as long as your country list isn't ridiculously large, making two separate method calls will make your code more readable and more maintainable. I like using LINQ to manipulate the in-memory collections.
I'd personally use one method to fetch the data.
private List<cDTOCountry> GetCountries()
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
return UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
}
And then later I'd process the data as needed:
var preMappedCountries = GetCountries();
var mappedCountries = preMappedCountries
.Select(c => Mapper.Map<cDTOCountry, cCountry>(c)) //map the data
.Skip(1) //skip the first element (the remove index 0)
.ToList(); //cast to List. Read more on LINQ's deferred execution.
var lastMatchingName = preMappedCountries
.LastOrDefault(c => c.Name == p); //gets the last country with matching name
The benefit to separating the logic into pieces is potential reuse of methods. If you ever find yourself needing to get data without mapping, you can do just that and skip all the LINQ logic. This way the logic that gets data is distinct from the logic that matches country names.
In your case an out param seems more appropriate. Otherwise as Kevin suggested you can return a Tuple.
I have a series of about 30 lookup tables in my database schema, all with the same layout (and I would prefer to keep them as separate tables rather than one lookup table), and thus my Linq2SQL context has 30 entities for these lookup tables.
I have a standard class that I would use for CRUD operations on each of these 30 entites, for example:
public class ExampleAttributes : IAttributeList
{
#region IAttributeList Members
public bool AddItem(string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = new ExampleAttribute();
a.Name = Item;
a.SortOrder = SortOrder;
context.ExampleAttributes.InsertOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool DeleteItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
if (a == null)
return true;
// Make sure nothing is using it
int Count = (from m in context.Businesses
where m.ExampleAttributeId == a.Id
select m).Count();
if (Count > 0)
return false;
// Delete the item
context.ExampleAttributes.DeleteOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool UpdateItem(int Id, string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
a.Name = Item;
a.SortOrder = SortOrder;
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public String GetItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
var Attribute = (from a in context.ExampleAttributes
where a.Id == Id
select a).FirstOrDefault();
return Attribute.Name;
}
public Dictionary<int, string> GetItems()
{
Dictionary<int, string> Attributes = new Dictionary<int, string>();
MyDataContext context = ContextHelper.GetContext();
context.ObjectTrackingEnabled = false;
Attributes = (from o in context.ExampleAttributes orderby o.Name select new { o.Id, o.Name }).AsEnumerable().ToDictionary(k => k.Id, v => v.Name);
return Attributes;
}
#endregion
}
I could replicate this class 30 times with very minor changes for each lookup entity, but that seems messy somehow - so can this class be genericised so I can also pass it the type I want, and have it handle internally the type differences in the linq queries? That way, I have one class to make additions to, one class to bug fix et al - seems the way that it should be done.
UPDATE:
Andrews answer below gave me the option that I was really looking at while thinking about the question (passing the type in) but I need more clarification on how to genericise the linq queries. Can anyone clarify this?
Cheers
Moo
There are a couple things you can try.
One is to define an interface that has all the relevant fields that the thirty entity classes share. Then, you would be able to have each entity class implement this interface (let's call it IMyEntity) by doing something like
public partial class EntityNumber1 : IMyEntity
{
}
for each entity (where EntityNumber1 is the name of one of the entity classes). Granted, this is still thirty different definitions, but your CRUD operation class could then operate on IMyEntity instead of having to write a new class each time.
A second way to do this is simply to genericize the CRUD operation class, as you suggest:
public class ExampleAttributes<T> : IAttributeList
{
...
which allows you to use T as the type on which to operate. Granted, this might be easier in combination with the first method, since you would still have to check for the presence of the attributes and cast the entity to the appropriate type or interface.
Edit:
To check for the presence of the appropriate properties on the entity, you might need to use reflection methods. One way to check whether the given type T has a particular property might be to check for
typeof(T).GetProperties().OfType<PropertyInfo>().Count<PropertyInfo>(pi => pi.Name == "MyPropertyName" && pi.GetGetMethod().ReturnType == typeof(TypeIWant)) > 0
Of course, replace TypeIWant with the type you are expecting the property to be, and replace MyPropertyName with the name of the property for which you are checking.
Add a parameter to the constructors which specifies the type. Then you can work with it internally. One class, with perhaps a switch statement in the constructor.
For genericising a LINQ query, the biggest problem is that your DataContext has the collections based on type. There are a few ways this can be circumvented. You could try to access it using reflection, but that will require quite a bit of hacking and would pretty much destroy all efficiency that LINQ to SQL would provide.
The easiest way seems to be to use Dynamic LINQ. I have not used it personally, but it seems like it should support it. You can find more information in this thread: Generic LINQ query predicate?
and on http://aspalliance.com/1569_Dynamic_LINQ_Part_1_Using_the_LINQ_Dynamic_Query_Library.1
Maybe someone else can provide more information about this?
This isn't necessarily an answer to the question, but may be a solution to your problem. Have you considered generating all the classes that you need? T4 is built into Visual Studio, and can generate code for you. The link below describes it fairly broadly, but contains heaps of links for further information.
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
That way, you can define all the methods in one place, and generate the class files for your 30-odd lookup models. One place to make changes etc.
Maybe worth considering, and if not, still worth knowing about.
I have a class called UserInfo that contains details about a given user.
There are several places in code where the data might be queried and I'd like to have a single function to fill the UserInfo object with the corresponding data from the Linq Query.
var userData = dc.Users.Where(λ => (λ.Login == username) && λ.Active)
.Select(λ => new { λ.ID, Salt = λ.Seasonings.Single().Salt, λ.Login, λ.PassHash, λ.Admin, λ.Trusted, λ.E_mail, λ.Name, λ.Phone, λ.Note, λ.RegistrationDate }).SingleOrDefault();
string tmppass = generatePassHash(password, userData.Salt);
if (userData.PassHash.Trim() == tmppass.Trim())
{
ID = userData.ID;
// Here is the stuff i'd like to move to a function
_user._id = userData.ID;
_user._userState = State.NotAuthorized;
_user._username = userData.Login;
_user._name = userData.Name;
_user._email = userData.E_mail;
_user._phone = userData.Phone;
_user._notes = userData.Note;
...
}
How do I properly set up a function to accept this anonymous type as an argument? Do I need to declare a new interface or is there a simpler way?
Thanks for the help!
PS- sorry for the excessive underscores, nested classes make things a bit messy.
For simplicity's sake, couldn't you just have all your routines accept the entity object itself? E.g. if dc.Users is a table of type UserEntity, skip the Select():
UserEntity userData = dc.Users.Where(
λ => (λ.Login == username) && λ.Active).SingleOrDefault();
And if that isn't acceptable, encapsulate a more limited object which takes UserEntity as a ctor parameter:
public class UserInfo
{
public string Name {get;set;}
public string Phone {get;set;}
...
public UserInfo(UserEntity entity)
{
this.Name = entity.Name;
this.Phone = entity.Phone;
...
}
}
var userData = dc.Users.Where(
λ => (λ.Login == username) && λ.Active).Select(
λ => new UserInfo(λ)).SingleOrDefault();
This abstracts the messy conversion away from the rest of your application. However, in general I'd recommend simply using the entity object, since it makes it much easier to go in reverse when you need (passing a modified entity back to the DAL).
I'm afraid It's not possible to pass an anonymous type as an argument to another method.
But I wonder why you are using an anonymous type and not working with user in the first place?
PS : BTW if you are applying the same pattern through out your code why don't you implement a concrete class for UserInfo ?