SPMETAL / LINQ to SharePoint Decimal Types - linq

I've hit a pretty major snag with the entities generated by spmetal / linq to sharepoint. I am hoping someone has dealt with this before.. or maybe I am missing something obvious.
Let's say we have a list with a number field. The field will be expected to hold reasonably precise values.. for example, 0.0000451. Once the value is in the list- SharePoint is fine with it. It displays in the list and display/edit views correctly.
Now if we generate entities based on this list with spmetal, we will get..
//...
private System.Nullable<double> _number;
//..
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="Number", Storage="_number", Required=true, FieldType="Number")]
public System.Nullable<double> Number {
get {
return this._number;
}
set {
if ((value != this._number))
{
this.OnPropertyChanging("Number", this._number);
this._number= value;
this.OnPropertyChanged("Number");
}
}
}
//...
Since the type determined by spmetal is doublewe get notation when trying to retrieve it.. for example:
var number = (from x in myDc.MyList select x.Number).First();
number would actually result in a double of 4.51E-05, not 0.0000451.
I am assuming this can be fixed by using a decimal. If I change the types throughout the generated entities to System.Nullable<decimal> I get type conversion failures.
How should I fix this?
EDIT I think maybe it is better to ask "how should I deal with this"? for example, I can simply convert my double values to decimal later on down the line.. my linq query, for example. If I do that, the example case would return the expected result. That seems clunky, though, and I'd like to correct this at the source.

There are several cases like this where SPMetal will give you clunky code. You can, and sometimes have to, fix that. And I admit, it definitely feels better to do it at the source.
But there is a downside.
When your data model changes you will have to re-run SPMetal to incorporate your new entities. Any changes you made to the generated file will have to be carefully documented and re-done, or your code will be broken. Therefore, I would advise to leave the generated code alone if you can work with it.
If you can write a wrapper around the objects/methods it would of course be preferable to just converting the types at the end-point, but that's general good programming practice.

4.51E-05 actually equals 0.0000451 so there is nothing wrong with your code.
In other words 4.51E-05 means 4.51 times ten to the minus five power, or 0.0000451

Related

Spring Data JPA fetching list always returns at least a single result

I've noticed a slight problem with how my API is working where I'm using Spring Data JPA.
My query looks something along the lines of:
#Query("SELECT p.id AS id, COUNT(l) AS likes FROM Post p LEFT JOIN Like l ON l.post = p WHERE p.location.id = ?1")
My actual query is bigger, this this contains everything necessary to explain what the issue is. This query will return a list, but assume the location does not exist, it should return null or an empty list, correct? Oh, how wrong you are, my sweet summer child!
This query will instead always return a list of at least one element, regardless of whether or not there are any posts linked to said location.
[{"id": null, "likes": 0}]
That is what the result looks like when serialized to JSON. I am not quite sure what to do about this little predicament, as I obviously don't want to return a list with faulty data, but needing to use processing to filter out duds also seems dumb and unnecessary.
Is there any way to prevent this that I've yet to find? If it is of any relevance, I am using projections currently for my responses.
What I've tried so far:
Adding a not null condition for fields. Does not work, ignored by COUNT.
Adding constraints to all fields #NotNull. Does not work, will still become null.
For what it's worth, I've tried different kinds of joins, though anything but LEFT JOIN doesn't make much sense.
I haven't been able to find any other case which resembles this either, although it most likely exists, but is drowned out by everything else. I'm not quite sure what can be done in this regard, so I'm curious if it's just a quirk with the framework, or if there is an actual solution.
It might be possible to solve through native queries, but I would prefer not to use them.
I'm no SQL expert but I believe that a left join will give you this result if the ID does not exist.
Have you run the query in your DB? Doesn't it give you one row in your result set for IDs that do not exist?
I believe this is intended to say there is a 0 match.
You might want to validate your query before running it. Meaning checking that the location exists first.
As the issue is inherently due to a COUNT and CASE keyword in my real query, resulting in there always being at least one row, and I can't find any method of doing this automatically, the solution I've used is the following:
List<Item> items = repository.customQuery(id);
if (0 < items.size() && null == items.get(0).getId()) {
items.remove(0);
}
The first condition is arbitrary as I know there is always at least one entry, but is done just as a safety measure. A try-catch block would do the trick as well. In the case where you use a primitive int instead of Integer, you'd need to initialize the value in the constructor to something which would normally never be present in the database, such as -1.
If anyone knows of a better method, I'd love to know about it.

DMQL2 Query Syntax for PHRets v2 Seach() to include filter arguments?

(It's been a while since I've been here.)
I've been using the first version of PHRets v1 for years, and understood it well enough to get by, but now I'm trying to understand the advantages of v2.6.2. I've got it all installed and the basics are working fine. My issues are pretty much with comprehending fine points of query syntax that goes into the rets=>Search() statement. (I'm much more familiar with SQL statements). Specifically, I'd like to have a query return a list of properties, EXCLUDING those which already have the status of "Sold".
Here's where I am stuck: If I start with this
`$results = $rets->Search('Property', 'A','*',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);`
That works well enough. BUT I'd like to fit in a filter like:
"LIST_15 != Sold", or "NOT LIST_15=Sold"...something like that. I don't get how to fit/type that into a PHRets Search().
I like PHRets but it is so hard to find well-organized/complete documentation about specific things like this. Thanks in advance.
As in my comment above I've figured out that the filter goes in the third argument position ('*', as in the original question). The tricky thing was having to find a specific "sold" code for each class of properties and placing it in that position like so: '(LIST_15=~B4ZIT1Y75TZ)', (notice the =~ combination of characters that means "does not equal" in this context). I've found the code strings for each of the property types (not clear WHY they would need to be unique for each type of property: "Sold" is Sold for any type, after all) but the correct code for a single-family residential property (type 'A' ...at least for the MLS in which I have to search is:
$results = $rets->Search('Property', 'A','(LIST_15=~B4ZIT1Y75TZ)',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);
(again, the code to go with LIST_15 will be different for the different types of properties.) I think there is a better answer that involves more naturalistic language, but this works and I guess I will have to be satisfied with it for now. I hope this is of some use to anyone else struggling with this stuff.

Leveraging spring to reduce DB calls

I have a data piece that is:
foo{
string: one
string: two
list<string>: listOne
list<string>: listTwo
}
such that in the DB one is associated with multiple entries of listOne.
not much background, I'm at a loss as to where to even look for answers. I received feed back to try to eliminate a jdbctemplate.query during a code review with a "there may be a way to reduce this using #autowire".
no code to share, I just need a place to start looking for answers. I've been on the spring website and I don't see anything that looks like I can use it. and I didn't see any google results that resemble what I'm looking for.
I should probably preface this with the fact that I'm a new dev so even a simple answer is likely not something I've tried. so this came about because my query for listOne and listTwo are returning columns. so I first tried using a mapper with the jdbcTemplate.query() that returned a string. but jdbc didn't like that. so I ended up returning a list from the mapper. then jdbc turns those answers into a list>, I then afterwards loop through those list> to convert them to a list and store them in foo. in my mind an ideal solution allows me to combine the two queries and the mapper looks like (pseudo code):
public foo fooMapper implements<RowMapper>(){
foo.one = resultSet.get("thingOne")
foo.two = resultSet.get("thingTwo")
foo.listOne = resultSet.get("[a portion of the column]listThingOne")
foo.listTwo = resultSet.get("[a portion of the column]listThingTwo")
return foo;
}
it should be noted that the the result set is mono-directional, I found out when I tried using a string[] instead of a list.

Report Builder Expressions

Im new to Report Builder and having issues with some expressions that Im trying to implement in a report. I got the standard ones to work however as soon as I try any distinctions, I get error messages. Over the last couple weeks, Ive tried many combinations, read the expression help, google and looking at other questions at internet sites. To reduce my frustrations, I even would jump to other expressions and walk away hoping I would have different insight coming back.
Its probably something simple or something I dont know about writing expressions.
Im hoping that someone can help with these expressions; they are the versions I get the least errors with(usually just expression expected) and show what Im trying to accomplish.
=IIF((Fields!RECORDFLAG.Value)='D',COUNTDISTINCT(Fields!TICKETNUM.Value),0)
=IIF((Fields!TRANSTYPE.Value)='1' and (Fields!RECORDFLAG.VALUE)='A' or
'B',SUM(Fields!DOLLARS.Value),0)
=IIF((Fields!TRANSTYPE.Value)='1' and
(Fields!RECORDFLAG.VALUE)='P',SUM(Fields!DOLLARS.Value),0)
=Sum([DOLLARS] case when [RECORDFLAG]='P' then -1*[DOLLARS])
Thank You.
=IIF((Fields!RECORDFLAG.Value)=”D”,COUNTDISTINCT(Fields!TICK‌​ETNUM.Value))
The error message gives you the answer here - no false part of the iif() has been specified. Use =IIF((Fields!RECORDFLAG.Value)=”D”,COUNTDISTINCT(Fields!TICK‌​ETNUM.Value), 0)
=IIF((Fields!TRANSTYPE.Value)="1" and (Fields!RECORDFLAG.VALUE)="A" or "B",SUM(Fields!DOLLARS.Value),0)
This is not how an OR works in SSRS. Use:
=IIF((Fields!TRANSTYPE.Value)="1" and (Fields!RECORDFLAG.VALUE="A" or Fields!RECORDFLAG.Value = "B"),SUM(Fields!DOLLARS.Value),0)
The 0s are returned due to your report design. countdistinct() is an aggregate function - it's meant to be used on a set of data. However, your iif() is only testing on a per row basis - you're basically saying "if the current row is thing, count all the distinct values" which doesn't make sense. There are a couple of ways forward:
You can count the number of times a certain value occurs in a given condition using a sum(). This is not the same as the countdistinct(), but if you use =sum(iif(Fields!RECORDFLAG.Value = "D", 1, 0)) then you will get the number of times RECORDFLAG is D in that set. Note: this requires the data to be aggregated (so in SSRS, grouped in a tablix).
You can use custom code to count distinct values in a set. See https://itsalocke.com/aggregate-on-a-lookup-in-ssrs/. You can apply this even if you have only one dataset - just reference the same one twice.
You can change the way your report works. You can group on Fields!RECORDFLAG.Value and filter the group to where Fields!RECORDFLAG.Value = "D". Then in your textbox, use =countdistinct(Fields!TICKETNUM.Value) to get the distinct values for TICKETNUM when RECORDFLAG is D.

SubSonic 3 Linq Join Problems

using the linqtemplates, I tried getting the linq syntax close to what is in the docs
var query = from c in db.CountyLookups
join s in db.StateLookUps on
c.StateLookupID equals
s.StateLookupID
where c.Name2 == countyName &&
s.Abbr == stateAbbr
select new
{
Latitude = c.Latitude,
Longitude = c.Longitude
};
var result = query.SingleOrDefault();
but when .SingleOrDefault() is called, I get a yellow screen of darn that says:
System.NotSupportedException: The member 'StateLookupID' is not supported
the stack trace ends up at:
SubSonic.Linq.Structure.TSqlFormatter.VisitMemberAccess(MemberExpression m)
the StateLookupID column has underscores in the database and is a regular int pk/fk.
what am I doing wrong?
So apparently VisitMemberAccess has no idea what to do with an int, only string and datetime (starting on line 152 of SubSonic.Linq.Structure.TSqlFormatter). I don't know why this would be called on a join, since a join is usually between an int pk/fk (or guid if you like).
I ended up scrapping the linq query in favor of SubSonic.Query.Select. Here is my new code that works:
var query = db.Select.From<CountyLookup>()
.InnerJoin<StateLookUp>()
.Where(CountyLookupTable.Name2Column)
.IsEqualTo(countyName)
.And(StateLookUpTable.AbbrColumn)
.IsEqualTo(stateAbbr);
I then call ExecuteTypedList and map the results back to my model class. Works like buttah. Just wanted to use linq in this case.
I get this error when I've added properties to my models (the IsValid property as mentioned in ASP.Net MVC 1.0, thanks Rob).
I've had this problem on and off for a bit, and I think I've got it nailed down to the query builder trying to build a query for something that should be done in code, not TSQL.
When it tries to generate the SQL, it descends down the path to generate the TSQL via VisitMemberAccess on a complex type (maybe a another model) but it only knows how to perform operations on datetimes and strings in VisitMemberAccess. I'm sorry if this is a bit incoherent, but I'm trying to get my head around it.
To get around this consider using something like LinqKit AsExpandable prior to any operation which will do the TSQL generation. I've tried this on a simple OrderBy which was going BANG and it appears to work but i have no idea yet what it will do to performance.
Actually I take that back I overcame my problem problem by doing
Stuff.All().Where(x=>x.Someid == id).ToArray()
.AsQueryable()
.Where(x=>x.SomeProp.SomeFlag == true);
It is crud, but it works.
This still appears to be a problem; namely in simple cases such as:
var list = from lang in db.Languages
join site in db.SiteConfigLanguages on
lang.Code equals site.LanguageCode
select lang;
This should evaluate to simple SQL (although pointless in this example):
SELECT Language.* FROM Language LEFT JOIN SiteConfigLanguage ON Language.Code = SiteConfigLanguage.LanguageCode;
It fails inside the same VisitMemberAccess function as (in this case) Language is not a recognisable declaring type (i.e. String or DateTime). It is very similar to the description #matware provided above however it sounds as though the "IsValid" member is pure C# code whereas in this case lang.Code is simply a reference to a column in the database.
I'm currently investigating workarounds as this is only a portion of the larger LINQ query which is failing for me; if I find anything I will post it here. Otherwise, any other solutions/workarounds to this problem known?
UPDATE: Ignore me here; this is simply due to me missing a simple line on the LINQ statement; you need to make sure that you use the "into" keyword to complete things!
i.e.
var list = from lang in db.Languages
join site in db.SiteConfigLanguages on
lang.Code equals site.LanguageCode into sl
from siteLang in sl.DefaultIfEmpty()
select lang;
I've got another error mind you but at least this particular exception is solved. The next one looks a bit nastier unfortunately (inside System.Linq library).

Resources