At long last, with the generics, lambdas and LINQ, C# is finally worth using. A bit restrictive at times, but OK.
čtvrtek 4. srpna 2011
enumerable.Distinct(IEqualityComparer what???
Now I understand years ago when there were no lambdas in C# and the syntax for function references (delegates for the C# folk) was so convoluted that they were almost unusable ... at those dark times all those IEqualityComparers and loads of other interfaces made some sense but now?
All I want is to filter some enumerable to get only the distinct values where distinct means the .ArticleId property is different (other properties either depend on ArticleId or are irrelevant and will not be used when processing the filtered list). Should be simple right?
I expected something like
var filtered = list.Distinct( (obj1, obj2) => obj1.ArticleId == obj2.ArticleId );
or even (as the ArticleId is a plain old int)
var filtered = list.Distinct( obj => obj.ArticleId );
Too simple.
...
private class DogsWithTheSameArticle : IEqualityComparer {
public bool Equals(WatchDogsToSend dog1, WatchDogsToSend dog2) {
return dog1.ArticleId == dog2.ArticleId;
}
public int GetHashCode(WatchDogsToSend dog) {
return dog.GetHashCode();
}
}
...
... many a line away ...
...
var filtered = notification.Distinct((IEqualityComparer)(new DogsWithTheSameArticle()));
OK. It works. But it's long and ugly, ugly, ugly.
Let us hide the insanity!
private class LambdaEqualityComparer : IEqualityComparer {
private Func _comparer;
public LambdaEqualityComparer(Func comparer) {
_comparer = comparer;
}
public bool Equals(T obj1, T obj2) {
return _comparer(obj1, obj2);
}
public int GetHashCode(T obj) {
return 0;
}
}
private class LambdaEqualityComparer : IEqualityComparer {
private Func _comparer;
private Func _selector;
public LambdaEqualityComparer(Func selector) {
_selector = selector;
_comparer = (obj1, obj2) => Object.ReferenceEquals(obj1, obj2) || obj1 != null && obj2 != null && selector(obj1).Equals(selector(obj2));
}
public bool Equals(T obj1, T obj2) {
return _comparer(obj1, obj2);
}
public int GetHashCode(T obj) {
return _selector(obj).GetHashCode();
}
}
///
/// Filters the enumerable to contain only distinct elements using a custom comparator.
///
/// a lambda that returns true if the two objects are to be considered equal
public static IEnumerable Distinct(this IEnumerable list, Func comparator) {
return list.Distinct(new LambdaEqualityComparer(comparator));
}
///
/// Filters the enumerable to contain only distinct elements using a custom comparator.
///
/// a lambda that extracts the value(s) to compare. If the selected values are equal, the objects are considered duplicate
public static IEnumerable Distinct(this IEnumerable list, Func selector) where TElem : IComparable {
return list.Distinct(new LambdaEqualityComparer(selector));
}
čtvrtek 21. července 2011
System.Web.Mvc.UpdateModel() throws exceptions after succeeding to update an object
Yes, the message is right. Even though the docs claim that it throws "System.InvalidOperationException: The model was not successfully updated."
The catch is that it throws the exception even if the model was successfully updated. Even if there was nothing to update at all. Even if there is a custom model binder for the type of the object you are trying to update, you step through the code and everything in the update works fine, all the properties are updated as they should, everything validates, the last line of your code returns exactly what it should and then KABOOOOM.
The model of type 'XXXXXX' could not be updated
Luckily in this particular case the source code is available so after some time with the sources of ASP.Net MVC you can find the reason. The (censored) who wrote the code decided to throw the exception whenever there is an error in the ModelState dictionary after updating the model. Sounds right, or not? Wait! What if there was something already before the UpdateModel() call? What if some other model failed, was handled and now I need to import some of the data into another object ... no way, as soon as there's an error, you get an exception. Your error, his error, their error, who the heck cares. Kabooom. Hooooray, we have an excuse to throw an exception!
Now if you don't really mind whether the update worked or not you can just use TryUpdateModel() and ignore the incorrect result. If you do care ... good luck.
The catch is that it throws the exception even if the model was successfully updated. Even if there was nothing to update at all. Even if there is a custom model binder for the type of the object you are trying to update, you step through the code and everything in the update works fine, all the properties are updated as they should, everything validates, the last line of your code returns exactly what it should and then KABOOOOM.
The model of type 'XXXXXX' could not be updated
Luckily in this particular case the source code is available so after some time with the sources of ASP.Net MVC you can find the reason. The (censored) who wrote the code decided to throw the exception whenever there is an error in the ModelState dictionary after updating the model. Sounds right, or not? Wait! What if there was something already before the UpdateModel() call? What if some other model failed, was handled and now I need to import some of the data into another object ... no way, as soon as there's an error, you get an exception. Your error, his error, their error, who the heck cares. Kabooom. Hooooray, we have an excuse to throw an exception!
Now if you don't really mind whether the update worked or not you can just use TryUpdateModel() and ignore the incorrect result. If you do care ... good luck.
čtvrtek 14. července 2011
MSSQL and WEEKDAY
OK. So you can set which day of the week is the "first" and then the DATEPART(weekday,@date) returns a number from 1 to 7 with the specified day being "1". The documentation is rather convoluted, but well ... what would you expect. So everything is nice and dandy isn't it?
No it is not. The catch is that the SET DATEFIRST is not stored with the stored procedure or function, but rather taken from the current connection. So you write for example a function that returns the first Monday at least N days after a specified date and ... pray that someone for whatever reason doesn't set DATEFIRST to anything else than it was set to when you tested the function. Cause the function doesn't remember what it was set to when it was parsed, you can't set it from within the function and there is no way to pass that option to DATEPART() explicitely.
Now that's what I call a stupid interface.
CREATE FUNCTION dbo.GetWeekDay(@Date datetime) RETURNS int
AS
BEGIN
Declare @day int
set @day = 1 + ((@@DATEFIRST + DATEPART( weekday, @Date) - 2) % 7);
return @day
END
go
At last something that's consistent. Agrrrrrr.
No it is not. The catch is that the SET DATEFIRST is not stored with the stored procedure or function, but rather taken from the current connection. So you write for example a function that returns the first Monday at least N days after a specified date and ... pray that someone for whatever reason doesn't set DATEFIRST to anything else than it was set to when you tested the function. Cause the function doesn't remember what it was set to when it was parsed, you can't set it from within the function and there is no way to pass that option to DATEPART() explicitely.
Now that's what I call a stupid interface.
CREATE FUNCTION dbo.GetWeekDay(@Date datetime) RETURNS int
AS
BEGIN
Declare @day int
set @day = 1 + ((@@DATEFIRST + DATEPART( weekday, @Date) - 2) % 7);
return @day
END
go
At last something that's consistent. Agrrrrrr.
pondělí 13. června 2011
Trailing slash in URLs
We are working on an eShop using ASP.Net MVC. The client wanted the URLs to look nice ... no big deal, URLs look nice in MVC, blah.com/detail/15, blah.com/category/45, ...
Not nice enough. We want the name of the article/category in the URL like this: blah.com/15/of_mice_and_men
OK, we are generating all URLs using MVC Futures so there's always some Html.Link("blah", MVC.Detail.Index(Model.ArticleId)) so how can I tweak this to generate that URL?
First thing ... make sure we accept them:
next we need to add the name to the RouteDataDictionary somehow. We could add the name as a parameter to the action (even though it doesn't need it) and call MVC.Detail.Index(Model.ArticleId, Model.ArticleName), but we have that on quite a few places already and we do not always have the name handy. Mkay, let's tweak some .tt In this case the T4MVC.tt. And let's do it in a gerenal way ... whenever there is a protected method RenderLink_<ActionName> in the controller, let's call it from the generated pseudoaction in the T4MVC_<ControlerName>Controller in the <ControllerName>Controller.generated.cs and let it tweak the RouteValueDictionary as needed.
Then all that is left is adding
into the controller and all URLs to details look as requested.
Until they come again that they want a slash at the end of the URL. OK, fine, but how? Including or not the slash in the MapRoute makes no difference. OK, the route object has some GetVirtualPath, is this what I need? I could let the inherited implementation to generate the URL and then append or insert (remember, there may be a query or hash in the URL!) the slash.
Now let's add (copy&paste&tweak) the extension methods to simplify adding the routes
and we have the slash :-)
Not nice enough. We want the name of the article/category in the URL like this: blah.com/15/of_mice_and_men
OK, we are generating all URLs using MVC Futures so there's always some Html.Link("blah", MVC.Detail.Index(Model.ArticleId)) so how can I tweak this to generate that URL?
First thing ... make sure we accept them:
routes.MapRoute( "Detail and name", "detail/{id}/{name}/", new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.Index }, new { id = @"^\d+$" });
next we need to add the name to the RouteDataDictionary somehow. We could add the name as a parameter to the action (even though it doesn't need it) and call MVC.Detail.Index(Model.ArticleId, Model.ArticleName), but we have that on quite a few places already and we do not always have the name handy. Mkay, let's tweak some .tt In this case the T4MVC.tt. And let's do it in a gerenal way ... whenever there is a protected method RenderLink_<ActionName> in the controller, let's call it from the generated pseudoaction in the T4MVC_<ControlerName>Controller in the <ControllerName>Controller.generated.cs and let it tweak the RouteValueDictionary as needed.
Then all that is left is adding
protected void RenderLink_Index(T4MVC_ActionResult callInfo) { if (callInfo.RouteValueDictionary.ContainsKey("id") && callInfo.RouteValueDictionary["id"] is int) { callInfo.AddRouteValue("name", Article.TitleForId((int)callInfo.RouteValueDictionary["id"]).EscapeForNiceUrl()); } }
into the controller and all URLs to details look as requested.
Until they come again that they want a slash at the end of the URL. OK, fine, but how? Including or not the slash in the MapRoute makes no difference. OK, the route object has some GetVirtualPath, is this what I need? I could let the inherited implementation to generate the URL and then append or insert (remember, there may be a query or hash in the URL!) the slash.
Now let's add (copy&paste&tweak) the extension methods to simplify adding the routes
public static class RouteCollectionExtensions {
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url) {
return MapRouteWithSlash(routes, name, url, null /* defaults */, (object)null /* constraints */);
}
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults) {
return MapRouteWithSlash(routes, name, url, defaults, (object)null /* constraints */);
}
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, object constraints) {
return MapRouteWithSlash(routes, name, url, defaults, constraints, null /* namespaces */);
}
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, string[] namespaces) {
return MapRouteWithSlash(routes, name, url, null /* defaults */, null /* constraints */, namespaces);
}
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, string[] namespaces) {
return MapRouteWithSlash(routes, name, url, defaults, null /* constraints */, namespaces);
}
public static Route MapRouteWithSlash(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
Route route = new RouteWithSlash(url, new System.Web.Mvc.MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
}
and
routes.MapRouteWithSlash(
"Detail and name",
"detail/{id}/{name}/",
new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.Index },
new { id = @"^\d+$" }
);
and we have the slash :-)
pondělí 4. dubna 2011
cannot derive from sealed type 'System.ComponentModel.EditorAttribute'
Yep, lovely. Yet another sealed class. Why?!?
OK, so I wrote a Visual Studio plugin that extends the Entity Framework designer. Everything's working fine. Well ... mostly ... the fact that if and only if there is a plugin, any validation problems in the updated .edmx are fatal and attributed to the plugin without the user having any chance to fix the problems ... in 99.784% of cases caused by the original code ... yeah, that's pretty annoying ... the only solution is to write a copy of the .edmx into a different file just before the EF Designer starts the validation and then replace the .edmx by this copy and fix the huge "Hey, I don't know what's the primary key for this view" problem.
Anyway ... most of the attributes I need to add to the properties that I want to display in the EF Designer are kinda OK. [DisplayName("...")], ["Description("...")], [Category("..")], [DefaultValue(...)]. All that's OK.
If I want a dropdown I just define an enum and it works automatically. (And if I want a dropdown with a dynamic list of options it ... well ... I haven't found a way to do that).
Then if I want a multiline input for the property, I know how to do it, it's just an attribute. An attribute that looks like this:
Lovely, isn't it?
OK, so I thought I could define subclass (named for example MultiLineAttribute) that'd use the inherited constructor with those values:
Why?!? Why the heck does the silly class have to be seaeaeaeaealed?
OK, so I wrote a Visual Studio plugin that extends the Entity Framework designer. Everything's working fine. Well ... mostly ... the fact that if and only if there is a plugin, any validation problems in the updated .edmx are fatal and attributed to the plugin without the user having any chance to fix the problems ... in 99.784% of cases caused by the original code ... yeah, that's pretty annoying ... the only solution is to write a copy of the .edmx into a different file just before the EF Designer starts the validation and then replace the .edmx by this copy and fix the huge "Hey, I don't know what's the primary key for this view" problem.
Anyway ... most of the attributes I need to add to the properties that I want to display in the EF Designer are kinda OK. [DisplayName("...")], ["Description("...")], [Category("..")], [DefaultValue(...)]. All that's OK.
If I want a dropdown I just define an enum and it works automatically. (And if I want a dropdown with a dynamic list of options it ... well ... I haven't found a way to do that).
Then if I want a multiline input for the property, I know how to do it, it's just an attribute. An attribute that looks like this:
[EditorAttribute(typeof(System.ComponentModel.Design.MultilineStringEditor),typeof(System.Drawing.Design.UITypeEditor))]
Lovely, isn't it?
OK, so I thought I could define subclass (named for example MultiLineAttribute) that'd use the inherited constructor with those values:
public class MultiLineAttribute : System.ComponentModel.EditorAttribute { public MultiLineAttribute() : base(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(System.Drawing.Design.UITypeEditor)) { } }Nope. Cannot derive from sealed type.
Why?!? Why the heck does the silly class have to be seaeaeaeaealed?
pátek 4. února 2011
LIKE in LINQ to Entities
For whatever reason there is (as far as Google searches suggest) no way to use LIKE in LINQ to Entities.
You can use LIKE in EntitySQL though so ... would you like a like in your LINQ?
No big deal actually.
Add
somewhere into the
You can use LIKE in EntitySQL though so ... would you like a like in your LINQ?
No big deal actually.
Add
<Function Name="String_Like" ReturnType="Edm.Boolean" ef4ex:RenameTo="Like"> <Parameter Name="searchingIn" Type="Edm.String" /> <Parameter Name="lookingFor" Type="Edm.String" /> <DefiningExpression> searchingIn LIKE lookingFor </DefiningExpression> <ef4ex:CodeBlock> throw new Exception("Not implemented"); </ef4ex:CodeBlock> </Function>
somewhere into the
<edmx:Runtime><edmx:ConceptualModels><Schema Namespace="Your.Namespace"
...>
and then
[System.Data.Objects.DataClasses.EdmFunction( "Your.Namespace", "String_Like")]public static Boolean Like(this String searchingIn, String lookingFor) {
throw new Exception("Not implemented");
}
into a static class (the name doesn't matter) in one the namespaces you tend to be "using" et voila ...
var results = db.EntitySet.Where(e => e.FooBarBaz.Like("%foo%bar%"));
Big deal, right? (Ignore or remove the ef4ex: attributes and tags, they are used by our customized template so that the C# code above gets generated automatically. If you decide to keep them add xmlns:ef4ex="http://jenda.krynicky.cz/schemas/EF4ex"
attribute into the root tag of the .edmx file.)
So what's the catch? There are two ... related.
First if you use two .edmx files in your project you either have to make sure you are only "using" one of the namespaces in each file (so that the compiler knows which extension method Like() do you mean) or have to rename one of the methods (in the C# code) so that you can access both, but then you have to make sure you always use the right one in each query.
The second is that you can't use this solution somewhere deep within a library that's to be reused with different projects. The Like() is tied fast to the .edmx. If I find a way to overcome this restriction, I'll update this post!
pondělí 10. ledna 2011
C# constructors
As usual, this is yet another in the series of complaints about C#, this time about constructors. Let me state right away that I do believe the syntax of constructors in C# is stupid. It comes as no surprise then that the syntax comes from C++. When it comes to syntax the authors of C and later C++ made quite a few stupid decisions, but I ain't gonna talk about the famous allaroundfix types of C or anything just now. So what do I hate about constructors in C#?
The fact that "A constructor looks very much like a method, but with no return type and a name which is the same as the name of the class". I don't mind the missing return type, what I do mind is the "name which is the same as the name of the class". Why? WHY? WHY?!? Why the fsck would I want to have to repeat the same name over and over again? Especially when constructors, unlike other methods are NOT inherited?
Does
class BlaBlaBlaBla : BleBleBle {
public BlaBlaBlaBla( Something one, OrOther two) : base(one, two) {}
ring a bell? This is annoying by itself, but the name of the class repeated as the name of the constructor, makes it about 134.7845% worse. Imagine you need to create several subclasses of a common parent! Instead of copying the first ten or so lines of the first subclass and changing JUST AND ONLY the class name on top, you have to change the name on several places. And then if you happen to add another constructor to the base class and want the subclasses to have it as well ... no, it's not automatic, not even a copy&paste job ... you have to go and change the stupid constructor name in each and every silly subclass.
Thank you very much!
It's funny that if I want to "call" one constructor from another, I do not have to repeat the name
public BlahBlahBlah(some parameters) : this() {
is enough. WHY? Or rather WHY isn't "this" enough on both places? Why couldn't it be
public this(some parameters) : this() {
Well it could not. It would be too convenient.
The fact that "A constructor looks very much like a method, but with no return type and a name which is the same as the name of the class". I don't mind the missing return type, what I do mind is the "name which is the same as the name of the class". Why? WHY? WHY?!? Why the fsck would I want to have to repeat the same name over and over again? Especially when constructors, unlike other methods are NOT inherited?
Does
class BlaBlaBlaBla : BleBleBle {
public BlaBlaBlaBla( Something one, OrOther two) : base(one, two) {}
ring a bell? This is annoying by itself, but the name of the class repeated as the name of the constructor, makes it about 134.7845% worse. Imagine you need to create several subclasses of a common parent! Instead of copying the first ten or so lines of the first subclass and changing JUST AND ONLY the class name on top, you have to change the name on several places. And then if you happen to add another constructor to the base class and want the subclasses to have it as well ... no, it's not automatic, not even a copy&paste job ... you have to go and change the stupid constructor name in each and every silly subclass.
Thank you very much!
It's funny that if I want to "call" one constructor from another, I do not have to repeat the name
public BlahBlahBlah(some parameters) : this() {
is enough. WHY? Or rather WHY isn't "this" enough on both places? Why couldn't it be
public this(some parameters) : this() {
Well it could not. It would be too convenient.
Přihlásit se k odběru:
Příspěvky (Atom)