Linq2SQL, cast in mapping? - linq

I am new to linq and linq2SQL. I have done my homework, i.e. found many results and answers that target similar problems. Seemingly lacking deeper understanding of linq and linq2SQL I am at my wits end.
I have a web application with a simple html and js frontend. I exchange data with my aspx via ajax xmlhttprequests. All the data naturally comes in and is supposed to go out as strings.
What I am trying to do:
private DateTime _date;
[Column(Storage = "_date", Name = "date", DbType = "date", CanBeNull = false)]
public string date
{
get { return this._date.ToString("yyyy-MM-dd"); }
set { this._date = DateTime.ParseExact(value, "yyyy-MM-dd", null); }
}
Instead of converting the string to a datetime in my aspx I would like to just pass on the strings and do the conversion at get and set. Running this code gives me an "invalid cast" error.
Am I trying to do something that is by desing simply not supposed to be done? Is my approach wrong? I don't expect someone else to write the code for me. I don't mind digging in the references, but I don't know where to start. So if someone where to point me in the right direction, I would greatly appreciate it.

Whatever the cast problem is, it is not in the code you are showing.
Converting to and from a DateTime value in a getter/setter is a perfectly reasonable thing to do. The only thing that could happen in your scenario is that you get a FormatException "String was not recognized as a valid DateTime." if the passed in value doesn't match a valid time string in your format - you currently do not handle this.

Solution for now:
[Column(Name = "date", DbType = "date", CanBeNull = false)]
public string date { get; set; }
Apperently linq or "whoever" is responsible can figure the casting out on it's own, if you let it. Right now that's good enough for me.
I have the feeling I will run into simliar casting problems later on and that different solutions may be required. If so I will update this thread.

Related

ElasticSearch / NEST 6 - Serialization of enums as strings in terms query

I've been trying to update to ES6 and NEST 6 and running into issues with NEST serializing of search requests - specifically serializing Terms queries where the underlying C# type is an enum.
I've got a Status enum mapped in my index as a Keyword, and correctly being stored in its string representation by using NEST.JsonNetSerializer and setting the contract json converter as per Elasticsearch / NEST 6 - storing enums as string
The issue comes when trying to search based on this Status enum. When I try to use a Terms query to specify multiple values, these values are being serialized as integers in the request and causing the search to find no results due to the type mismatch.
Interestingly the enum is serialized correctly as a string in a Term query, so I'm theorizing that the StringEnumConverter is being ignored in a scenario where it's having to serialize a collection of enums rather than a single enum.
Lets show it a little more clearly in code. Here's the enum and the (simplified) model used to define the index:
public enum CampaignStatus
{
Active = 0,
Sold = 1,
Withdrawn = 2
}
public class SalesCampaignSearchModel
{
[Keyword]
public Guid Id { get; set; }
[Keyword(DocValues = true)]
public CampaignStatus CampaignStatus { get; set; }
}
Here's a snippet of constructing the settings for the ElasticClient:
var pool = new SingleNodeConnectionPool(new Uri(nodeUri));
var connectionSettings = new ConnectionSettings(pool, (builtin, serializerSettings) =>
new JsonNetSerializer(builtin,
serializerSettings,
contractJsonConverters: new JsonConverter[]{new StringEnumConverter()}
)
)
.EnableHttpCompression();
Here's the Term query that correctly returns results:
var singleTermFilterQuery = new SearchDescriptor<SalesCampaignSearchModel>()
.Query(x => x.Term(y => y.Field(z => z.CampaignStatus).Value(CampaignStatus.Active)));
Generating the request:
{
"query": {
"term": {
"campaignStatus": {
"value": "Active"
}
}
}
}
Here's the Terms query that does not return results:
var termsFilterQuery = new SearchDescriptor<SalesCampaignSearchModel>()
.Query(x => x.Terms(y => y.Field(z => z.CampaignStatus).Terms(CampaignStatus.Active, CampaignStatus.Sold)));
Generating the request:
{
"query": {
"terms": {
"campaignStatus": [
0,
1
]
}
}
}
So far I've had a pretty good poke around at the options being presented by the JsonNetSerializer, tried a bunch of the available attributes (NEST.StringEnumAttribute, [JsonConverter(typeof(StringEnumConverter))] rather than using the global one on the client, having an explicit filter object with ItemConverterType set on the collection of CampaignStatuses, etc.) and the only thing that has had any success was a very brute-force .ToString() every time I need to query on an enum.
These are toy examples from a reasonably extensive codebase that I'm trying to migrate across to NEST 6, so what I'm wanting is to be able to specify global configuration somewhere rather than multiple developer teams needing to be mindful of this kind of eccentricity.
So yeah... I've been looking at this for a couple of days now. Good chances there's something silly I've missed. Otherwise I'm wondering if I need to be providing some JsonConverter with a contract that would match to an arbitrary collection of enums, and whether NEST and their tweaked Json.NET serializer should just be doing that kind of recursive resolution out of the box already.
Any help would be greatly appreciated, as I'm going a bit crazy with this one.

For some reason I got Code Analysis errors that are supressed

For exmaple I got error:
CA1056 URI properties should not be strings Change the type of property 'CoreCallbackServiceConfiguration.UriTemplate' from string to System.Uri.
for propery
[SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "The template should be string")]
[DataMember(Name = "uriTemplate")]
public string UriTemplate { get; set; }
you see that there is supress atribute but I still got error. Other people in my team doesn't get this errors. Any ideas?
The following works for me:
[SuppressMessage("Design", "CA1056:Uri properties should not be strings", Justification = "This is a DB table field")]
Keep in mind I'm using this in .NET Core 3. I'm not sure if the analyzers are the same for other versions of .NET.

Better way to handle this code

I am working on a MVC3 application with nhibernate and SQL server. Have written a normal method which is re-usable. Please find the below code and let me know a better way to handle it. I have observed to execute this piece of code it is taking a long time.
private void GetParentCompany(IEnumerable<Company> companiesList)
{
foreach (var company in companiesList)
{
long? dunsUltimateParent = company.DUNSUltimateParent;
Company ultimateParent = _companyService.GetCompanyByDUNS(Convert.ToInt64(dunsUltimateParent));
if (ultimateParent != null)
{
company.UltimateParentName = ultimateParent.CompanyName;
company.UltimateCompanyId = ultimateParent.CompanyId;
company.UltimateParentDuns = ultimateParent.DUNS;
}
}
}
Adding an index to your company.DUNS column might help. However consider to introduce a many-to-one relationship from company to (parent) company.
Place a UltimateParent property with type company in the company class. The fields UltimateParentName and UltimateParentDuns would then be redundant and you could simply get company.UltimateParent.Name for example. The mapping of UltimateParent can be done using 'References' in fluent-nhibernate.
References(x => x.UltimateParent);

ASP.NET MVC Converting null to zero-length string

I'm using MVC 3 and attempting to get fields left blank to be sent to the database as zero-length strings, instead of nulls. Is this possible to do with data annotation attributes?
If not, what is the most appropriate place to convert from nulls? Is it during model validation?
While not ideal, this is the best way I know of: [DisplayFormat(ConvertEmptyStringToNull = false)] above the property. It keeps the logic in the model, which is good practice, and it directly addresses the issue. It's just a bummer that this is necessary.
private string _summary = "";
[Required]
[DisplayFormat(ConvertEmptyStringToNull = false)]
public virtual string Summary
{
get { return _summary; }
set { _summary = value; }
}
I wouldn't do this in a validator, but probably in model binding instead (or even in the model itself).
Often, in my model classes, I set my string properties to default to an empty string, and in their setters, I convert nulls to empty strings.
It's kindof a pain to write this repetitive stuff over and over, but it's so much nicer to not have to deal with nulls.
Set the property equal to string.empty in the constructor.
Or, though this is a little more costly you could make an extension method that does the following and just call it in the constructor:
var stringPropertyInfos = GetType()
.GetProperties(BindingFlags.Instance|BindingFlags.Public)
.Where(p => p.PropertyType == typeof(string));
foreach(var propertyInfo in stringPropertyInfos){
propertyInfo.SetValue(this,string.Empty,null);
}

linq (to nhibernate) where clause on dynamic property in sql

My entity has a property which is derived from other properties
public class MyClass
{
public DateTime Deadline { get; set; }
public Severity Severity
{
return (DateTime.Now - Deadline < new TimeSpan(5, 0, 0, 0)) ? Severity.High : Severity.Low;
}
}
is there a way I can modify the following
return repository.Query().Where(myClass => myClass.Severity == High);
so that the where clause evaluates in sql rather than in code?
I tried to do something like this, but to no avail
public class MyClass
{
public DateTime Deadline { get; set; }
public Func<MyClass, bool> SeverityFunc = (DateTime.Now - Deadline < new TimeSpan(5, 0, 0, 0)) ? Severity.High : Severity.Low;
public Severity Severity
{
return SeverityFunc.Invoke(this);
}
}
return repository.Query().Where(myClass => myClass.SeverityFunc(myclass) == High);
I'm guessing because the func cant be evaluated to SQL. Is there some other way to do this without ending up with duplicate calculations for severity
Any help appreciated, ta
Edit: This is a simplified version of what im trying to do, i'm looking for answers that cover the theory of this rather than a specific fix (though still welcome). Im interested in whats possible, and best practices to achieve this sort of thing.
Andrew
I have used something similar on a mapper. Make sure to wrap the Func on on Expr, like:
public Expr<Func<MyClass, bool>> SeverityFunc ...
By wrapping it with expr linq2sql will be able to look at the full expression and translate appropiately. I haven't used it as part of a class instance like the one you have, so I am not sure how that would affect it.
Regarding on where to put it, I had to move on the last time I worked on a similar scenario, in my case it ended up in the mapper, but mostly because it was more a mapping concern from an awfully database schema than domain logic. I didn't even had the property dynamically calculated on the domain entity for that matter (a different scenario for sure).
One option is the LINQ Dynamic Query Library, See http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Another option is to use the PredicateBuilder from http://www.albahari.com/nutshell/predicatebuilder.aspx
Hope this answers your question,
Roelof.

Resources