Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am new to both SPA and Entity Framework and I have a question about the right/preferred way to do this.
I've got a web page to search customers by some filters (like name, surname, birthday date, phone number).
With ajax I pass from View to Controller a ViewModel object like this:
public class CustomerSearch
{
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? Birthday{ get; set; }
public string Phone{ get; set; }
}
Into controller I've got this search method:
public List<CustomerList> GetCustomersList(CustomerSearch cs)
{ ..... }
In my application there are also DataAccess objects.
Now, the question is: how I can to do the query to database in smart mode?
I've thinked some scenario but i don't know which is the best about the layer separation.
I can ask to model an IQueryable object and perform the Where condition into controller
I can create a DataAccess method with the filters like parameters
I can create a Customer object (model object) filled with the filters value and pass this to model that perform the query
Which is the best method?
Thanks in advance.
Daniele
I would suggest the first option you present for the following reasons:
Your second option would possibly require a lot of parameters if the number of possible search queries grows. It is generally not recommended to have a very large number of parameters since it leads to readability issues. (e.g. calling a method with 30 parameters)
Your third option would make it impossible to create a query like 'BirthDate in 1998' or 'Surname starts with Q'.
By creating a class specifically for the purposes of querying you can do something like the following:
public class CustomerQuery
{
public string Name { get; set; }
public DateTime? BirthDay { get; set; }
internal IQueryable<Customer> Apply(IQueryable<Customer> query)
{
var result = query;
if (!string.IsNullOrWhiteSpace(Name))
{
result = result.Where(c => c.Name == Name);
}
if (BirthDay.HasValue)
{
result = result.Where(c => c.BirthDay == BirthDay.Value);
}
return result;
}
}
Pay specific attention to the internal visibility of the Apply method. If you define this class in your Data Access Layer and this is defined in a separate C# project, the Apply method will only be visible to this Data Access Layer and not to the GUI project.
Calling it would be:
public List<Customer> GetCustomersList(CustomerQuery customerQuery)
{
using (var context = new MyDbContext())
{
var customers = context.Customers;
return customerQuery.Apply(customers).ToList();
}
}
This can be further extended to support e.g. different types of string search (Contains, StartsWith etc):
public enum TextFilterType
{
StartsWith,
EndsWith,
Contains,
ExactMatch
}
public class StringQuery
{
private readonly string _value;
private readonly TextFilterType _filterType;
public StringQuery(string value, TextFilterType filterType)
{
_value = value;
_filterType = filterType;
}
public string Value
{
get { return _value; }
}
public TextFilterType FilterType
{
get { return _filterType; }
}
}
If we would apply this to the CustomerQuery type:
public class CustomerQuery
{
public StringQuery Name { get; set; }
}
Then you look at the FilterType property of the StringQuery to find out if you need to do Contains, StartsWith etc.
Related
This question already has answers here:
Return multiple values to a method caller
(28 answers)
Closed 7 months ago.
Code snippet:
var pMessageId = p.Get<byte[]>("p_message_id");
var pContentId = p.Get<byte[]>("p_content_id");
if (pMessageId != null && pContentId != null)
{
var result = new Guid(pMessageId);
var secondResult = new Guid(pContentId);
await transaction.CommitAsync(cancellationToken);
return
}
I want to return two guid values at once (result, secondResult). How do I do that?
Use a value tuple:
public (Guid Result, Guid SecondResult) MyMethod(){
...
return (result, secondResult);
}
The issue with "Tuple" is that your values are accessible by .Item1, .Item2.
IMHO, you mortgage future maintainability for a quick fix.
(That part is opinion based).
But technically, one way to solve it is to create a simple Poco. (Aka, start no opinion area)
public sealed class GuidHolder
public Guid GuidOne { set; get; }
public Guid GuidTwo { set; get; }
}
or a more "convenient" version
public sealed class GuidHolder
public GuidHolder() : this(Guid.NewGuid() , Guid.NewGuid() )
{}
public GuidHolder(Guid g1, Guid g2)
{
this.GuidOne = g1;
this.GuidTwo = g2;
}
public Guid GuidOne { private set; get; }
public Guid GuidTwo { private set; get; }
}
So the above is a no opinion technical answer.
Back to opinion:
IMHO, (the above poco's are) 3 minutes of work. Now your code is more readable for the future.
When your code base is riddled with ".Item1" .. "ItemN" code.....is becomes difficult to maintain. Aka, mortgage the future maintainability to save 3 minutes of work.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
When Domain Model property Name gets data from the database it's a string "David,James", but I have created another View Model to convert that string into an array ["David","James"]. I have used my ViewModel in the read method now, now the ViewModel should read the Name property as ["David","James"]. I am not sure how to make it happen.
I would appreciate if anybody has any suggestion on how to make it happen.
Domain Model:
public class FullName
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Address {get; set;}
}
View Model:
public class NameViewModel
{
public Int32 Id { get; set; }
public List<string> Name { get; set; }
public String Address { get; set;}
}
Read Method:
public ActionResult Name_Read([DataSourceRequest]DataSourceRequest request)
{
try
{
DataSourceResult result = Identity.ToDataSourceResult(request, NameViewModel => new
{
Id = NameViewModel.Id,
Name = NameViewModel.Name ,
Address = NameViewModel.Address,
});
return Json(result);
}
I think you're looking for something like this:
DataSourceResult result = Identity.ToDataSourceResult(request, dataModel => new NameViewModel
{
Id = dataModel.Id,
Name = dataModel.Name.Split(","),
Address = dataModel.Address,
});
// typical delimiter characters
char[] delimiterChars = { ' ' };
// verify the name exists
if (!String.IsNullOrEmpty(name))
{
// Get the list of strings
string[] strings = name.Split(delimiterChars);
if (strings != null)
{
if (strings.Length == 1)
{
firstName = strings[0];
}
else if (strings.Length == 2)
{
firstName = strings[0];
lastName = strings[1];
}
else if (strings.Length == 3)
{
firstName = strings[0];
middleName = strings[1];
lastName = strings[2];
}
}
}
I am not at Visual Studio, but I think that is right.
When Domain Model property Name gets data from the database it's a string "David,James"
That is a terrible mistake in database Design. The ideal solution would be to fix the Backend Database to actually have two fields for those distinct values.
Failing that, the next step would be to try and split on the DB side. Many modern DBMS support Views, wich can have columns computed from actuall rows. That way you could avoid issues, like different code splitting the same input differently. And you could even henceforth treat it like it was always two Columns.
If you really want or need to it in code and given this exact input format, String.Split() can deal with this. Of coruse you can get fancier, and use stuff like Regular Expressions instead. But for this example, Split seems perfectly suiteable for the case.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I'm using a web service with this request format:
{
"type":"LogonReq",
"id":"b43b301c-5216-4254-b3fc-cc863d4d6652",
"date":"Wed, 16 Aug 2017 17:35:34 UTC",
"parameters":[
{
"userName":"user",
"password":"password"
}
]
}
Even though every message in the API requires only 1 set of parameters, the API still requires "parameters" to be an array.
Is it better practice to have the caller create the list or to create the list in the MessageBase constructor, or something altogether different ?
Which way would satisfy an OOP purist code reviewer?
public class MessageBase<T>
{
public MessageBase() { this.parameters = new List<T>(); }
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
};
logon.parameters.Add(new LogonMessage() { userName = "user", password = "password" });
or
public class MessageBase<T>
{
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
parameters = new List<LogonMessage>() { new LogonMessage() { userName = "user", password = "password" } }
};
You will probably find many interesting opinions and answers to this. I can only give you mine based on my experience.
I myself would probably initialize the list within the constructor
However, since you are trying to get a good idea around the phylosophy of coding, here are some things to consider :
1) Does the MessageBase object make sense or is it useful with a NULL list? Is there any scenario where I want this list as null?
2) Actually, I would expect an OOP purist to say that you should not expose the "parameters" as a List. By exposing the object as a property, someone can do this:
login.parameters.Add()
Or this
logon.parameters = anotherListOfMine
In a way it does break encapsulation. You could make the list property read only (ie, with a protected/private setter) but "clients" of this class will still be able to access all properties and methods of the List and modify/handle them.
Now, you have to expose this in some way as you will be serializing/deserializing into JSON, so that poses a problem! Maybe you can have a private/protected List field and expose the values through a readonly property that exposes an IEnumerable and behind the scenes, you are doing:
get { return myPrivateList.ToArray(); }
3) But again, do you really win that much? Your next question should be "Who is my client?" If you are exposing this class to other developers, or is part of a framework, you might want to apply something like my point number 2, and limit the exposure. If this is internal to your application and your team maybe you should be pragmatic and simply expose the List as you are doing right now.
4) Alternatively, while still making it open, you could instead have a property of type IEnumerable so you can pass in any type.
5) Another option is to expose your list because you need to serialize it, but make it readonly. Have instead different methods, or non-serializable properties, of username and password. If these parameters are always the same that is. I am thinking this might not be your case.
I think I could go on and on this. I will stop here before you hit the downvote button :).
Hi I'm having difficulty finding an answer to my question here, so I figured I'd just ask. I have to lists of classes, ServiceItem, and ServiceDetailsClass. I want to filter out all of the ServiceDetailClass Items that are not int ServiceItems list. Here are the two classes:
public class ServiceItem
{
public long ID { get; set; }
public string Status { get; set; }
}
public class ServiceDetailsClass
{
public string Name;
public long ID;
public int Quantity;
public string Notes;
public string Status;
public string Description;
public DateTime CreatedDate;
}
So far the only things I've found on here is for lists that have a list in them, so this is a bit different. This is all I was able to come up with, but the filter list has 0 item, even though I know it should have more than that:
lstFilteredServiceDetailsClass = lstServiceDetailsClass.Where(i => lstServiceItem.Contains
(new ServiceItem { lngId = i.ServiceID, strStatus = "Locked" })
Any help is appreciated. Thanks!
You're making a new object and then checking the list to see if that exact object/instance is in it (i.e. because it's an object, it's comparing the reference).
Instead, you need to look for overlapping IDs.
Something like this should work:
List<ServiceItem> serviceItems;
List<ServiceItemDetails> serviceItemDetails;
var result = serviceItemDetails.Where(sid => serviceItems.Any(si => si.ID == sid.ID))
In English: "The collection of ServiceItemDetails where the list of service items has an item with the same ID"
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
Let's say I have two classes like
public partial class dbUserDetails
{
public int Id { get; set; }
[AllowHtml]
public string Bio { get; set; }
//some properties
}
public partial class SomeOtherClass
{
[DisplayName("Profile Picture (max. 2MB)")]
public HttpPostedFileBase File { get; set; }
//some properties
}
And I want to combine some properties like
public class Settings
{
//HttpPostedFileBase File
//public string Bio { get; set; }
}
Razor:
#model myAppp.Models.Settings
#Html.EditorFor(m => m.Bio)
#Html.EditorFor(m => m.File)
Is it possible to use in this way? I know something about interface and partial. But I dont know how i will exactly figure out.
For this to work you would have to pass the information from dbUserDetails and SomeOtherClass to you Settings class. The easiest way for this would be to simply create the Settings class with instances of the two other classes and make them available as properties:
public class Settings{
private dbUserDetails userDetails;
public dbUserDetails UserDetails {
return userDetails;
}
private SomeOtherClass someOtherInfo;
public SomeOtherClass SomeOtherInfo{
return someOtherInfo;
}
public Settings(dbUserDetails user, SomeOtherInfo other) {
userDetails = user;
someOtherInfo = other;
}
}
Now you can access them this way: m => m.UserDetails.Bio
I did it via this way of accessing and not the way you mentioned before (direct access) because you would otherwise have the property duplicated at two positions. I would only do that if there was a good reason for this.
Edit:
For some clarification on why I chose the above written code:
Storing the dbUserDetails and SomeOtherClass objects in Settings does not create significant memory overhead at this point. All their properties should be accessible using Settings to they have to be stored somewhere. Therefore I decided to just leave them where they are.
A memory problem would only occur if the two classes stored more information than you want to make accessible and are not used anymore so that they could be deleted. In this case it would make sense to actually copy the information like this:
public class Settings{
private string bio;
public string Bio {
return bio;
}
/*...*/
public Settings(dbUserDetails user, SomeOtherInfo other)
{
bio = user.Bio;
/*...*/
}
}
If you do not delete the two aforementioned objects when doing this, you store the information twice (=> memory overhead). This is worse than just storing references to the objects.
Another option would be this:
public class Settings{
private dbUserDetails userDetails;
public string Bio {
return userDetails.Bio;
}
public Settings(dbUserDetails user, SomeOtherInfo other)
{
userDetails = user;
/*...*/
}
}
This would be the same idea as the first one but with direct access to the properties. It would work as well but lead to more code duplication. Each new property in the sub objects would lead to a property in Settings