<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8627092016055243145</id><updated>2012-01-23T11:58:41.571+01:00</updated><category term='ruby'/><category term='linux'/><category term='Design patterns'/><category term='projektstruktur'/><category term='VMWare'/><category term='MVC'/><category term='Get'/><category term='web'/><category term='Mappning'/><category term='Repository'/><category term='Hobbyprojekt'/><category term='Design'/><category term='django'/><category term='Model binding'/><category term='Template pattern'/><category term='C#'/><category term='Interfaces'/><category term='VM'/><category term='Domain Queries'/><category term='python'/><category term='Linq'/><category term='Extension Methods'/><category term='hobby'/><category term='NHibernate'/><category term='framtid'/><category term='windows'/><category term='Fluent NHibernate'/><category term='virtuellt'/><category term='Load'/><category term='Databas'/><category term='Criteria'/><category term='Html'/><category term='Conventions'/><category term='problem'/><title type='text'>kny#</title><subtitle type='html'>Coding adventures in C#</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-5148970692390524186</id><published>2010-03-31T10:24:00.000+02:00</published><updated>2010-03-31T10:24:08.077+02:00</updated><title type='text'>Moving!</title><content type='html'>Yes, as the title above says, i'm moving my blog posts to &lt;a href="http://www.codejunkies.se"&gt;www.codejunkies.se&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;CodeJunkies is a collaboration of friends with coding as a passion. We decided to group all our various blogs to one bigger (and hopefully better and more interesting) blog. Sooo, what are you waiting for, head over there now! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-5148970692390524186?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/5148970692390524186/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/03/moving.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/5148970692390524186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/5148970692390524186'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/03/moving.html' title='Moving!'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-9151393862730801972</id><published>2010-02-03T13:15:00.014+01:00</published><updated>2010-02-03T15:27:22.569+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Extension Methods'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Html'/><title type='text'>Meet my new HtmlHelper extensions friends, ForEach and If</title><content type='html'>How many times have you written code like this in your MVC views?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;%&lt;br /&gt; int currentIndex = 0;&lt;br /&gt; foreach(var item in Model.Items) {&lt;br /&gt;%&amp;gt;&lt;br /&gt;    &amp;lt;% if(currentIndex == 0) {%&amp;gt;&lt;br /&gt;       &amp;lt;div class=&amp;quot;item first&amp;quot;&amp;gt;&amp;lt;%= item.Name %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;% } else if(currentIndex == Items.Count()-1) { %&amp;gt;&lt;br /&gt;       &amp;lt;div class=&amp;quot;item last&amp;quot;&amp;gt;&amp;lt;%= currentIndex + 1 %&amp;gt; &amp;lt;%= item.Name %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;% } else { %&amp;gt;&lt;br /&gt;       &amp;lt;div class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;%= item.Name %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;% } %&amp;gt;&lt;br /&gt;&amp;lt;%&lt;br /&gt; currentIndex++;&lt;br /&gt; }&lt;br /&gt;%&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is pure ugliness :(&lt;br /&gt;&lt;br /&gt;What I missed was something like &lt;a href="http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for"&gt;django for variables&lt;/a&gt;. They include both a Last and First variable on the loop.&lt;br /&gt;&lt;br /&gt;After reading Phil Haacked's blog about &lt;a href="http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx"&gt;"A code based repeater for .NET MVC"&lt;/a&gt; I decided to shamelessy take some parts of his code and write my own extension methods.&lt;br /&gt;&lt;br /&gt;The first extension method I wrote was the Html.ForEach which gets me a index counter.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public static void ForEach&amp;lt;T&amp;gt;(this HtmlHelper html, IEnumerable&amp;lt;T&amp;gt; items, Action&amp;lt;T, int&amp;gt; render)&lt;br /&gt;{&lt;br /&gt;    if (items == null)&lt;br /&gt;        return;&lt;br /&gt;&lt;br /&gt;    int i = 0;&lt;br /&gt;    items.ForEach(item =&amp;gt; render(item, i++));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And to use it&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;% Html.ForEach(Model.Items, (item, index) =&amp;gt; { %&amp;gt;&lt;br /&gt;    &amp;lt;div&amp;gt;#&amp;lt;%= index + 1 %&amp;gt; &amp;lt;%= item.Name %&amp;gt;&lt;br /&gt;&amp;lt;% }); %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pretty slick and I dont need to have the counter variable in the view code. It uses lambda in way I didn't thought was possible before I read Haacked blog post.&lt;br /&gt;&lt;br /&gt;I then decided to see if I could manage to check if I was on the first or last item in the loop.&lt;br /&gt;&lt;br /&gt;I came up with this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public static void ForEachExtra&amp;lt;T&amp;gt;(this HtmlHelper html, IEnumerable&amp;lt;T&amp;gt; items, Action&amp;lt;T, ForLoop&amp;lt;T&amp;gt;&amp;gt; render)&lt;br /&gt;{&lt;br /&gt;    if (items == null)&lt;br /&gt;       return;&lt;br /&gt;&lt;br /&gt;    var loop = new ForLoop&amp;lt;T&amp;gt;(items);&lt;br /&gt;&lt;br /&gt;    int i = 0;&lt;br /&gt;    items.ForEach(item =&amp;gt; { render(item, loop.Update(i)); i++; });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ForLoop&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private readonly int _itemCount;&lt;br /&gt;&lt;br /&gt;    public ForLoop(IEnumerable&amp;lt;T&amp;gt; items)&lt;br /&gt;    {&lt;br /&gt;        _itemCount = items.Count();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int Counter { get; set; }&lt;br /&gt;    public int Counter0 { get; set; }&lt;br /&gt;    public bool First { get; set; }&lt;br /&gt;    public bool Last { get; set; }&lt;br /&gt;&lt;br /&gt;    public ForLoop&amp;lt;T&amp;gt; Update(int i)&lt;br /&gt;    {&lt;br /&gt;        Counter = i + 1;&lt;br /&gt;        Counter0 = i;&lt;br /&gt;        First = i == 0;&lt;br /&gt;        Last = i == _itemCount-1;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And to use this you will write&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;% Html.ForEachExtra(Model.Templates, (template, loop) =&amp;gt; {%&amp;gt;&lt;br /&gt;   &amp;lt;% if(loop.First) { %&amp;gt; First! &amp;lt;% }%&amp;gt;"&gt;&lt;br /&gt;   &amp;lt;div&amp;gt;#&amp;lt;%= loop.Counter %&amp;gt; - &amp;lt;%= template.Name %&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;   &amp;lt;% if(loop.Last) { %&amp;gt; Last! &amp;lt;% }%&amp;gt;&lt;br /&gt;&amp;lt;% }); %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Starting to look impressive here! :) But I still think I can get it better, so onto my other new extension method, If()!&lt;br /&gt;&lt;br /&gt;What I want is to have code that looks something like this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;% Html.ForEachExtra(Model.Items, (item, loop) =&amp;gt; { %&amp;gt;&lt;br /&gt;   &amp;lt;div class=&amp;quot;item &amp;lt;%= Html.If(loop.First).Write(&amp;quot;first&amp;quot;).ElseIf(loop.Last).Write(&amp;quot;last&amp;quot;) %&amp;gt;&lt;br /&gt;       #&amp;lt;%=loop.counter%&amp;gt; &amp;lt;%= item.Name %&amp;gt;&lt;br /&gt;   &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;% }); %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That would be awesome so off I went to write it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface IConditionWrite&lt;br /&gt;{&lt;br /&gt;    IElseIfConditionBuilder Write(string output);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface IElseIfConditionBuilder&lt;br /&gt;{&lt;br /&gt;    IConditionWrite ElseIf(bool condition);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ConditionBuilder : IConditionWrite, IElseIfConditionBuilder&lt;br /&gt;{&lt;br /&gt;    private readonly IList&amp;lt;FluentHtmlCondition&amp;gt; _conditions;&lt;br /&gt;    private FluentHtmlCondition _lastAddedCondition;&lt;br /&gt;&lt;br /&gt;    public ConditionBuilder()&lt;br /&gt;    {&lt;br /&gt;        _conditions = new List&amp;lt;FluentHtmlCondition&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public IConditionWrite AddCondition(FluentHtmlCondition condition)&lt;br /&gt;    {&lt;br /&gt;       _lastAddedCondition = condition;&lt;br /&gt;       _conditions.Add(condition);&lt;br /&gt;       return this;&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    public override string ToString()&lt;br /&gt;    {&lt;br /&gt;        foreach (var condition in _conditions) {&lt;br /&gt;            if (condition.Fulfilled)&lt;br /&gt;                return condition.Output;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return &amp;quot;&amp;quot;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public IConditionWrite ElseIf(bool condition)&lt;br /&gt;    {&lt;br /&gt;        AddCondition(new FluentHtmlCondition(condition));&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public IElseIfConditionBuilder Write(string output)&lt;br /&gt;    {&lt;br /&gt;        _lastAddedCondition.Output = output;&lt;br /&gt;        return this;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class FluentHtmlCondition&lt;br /&gt;{&lt;br /&gt;    public readonly bool Fulfilled;&lt;br /&gt;    public string Output;&lt;br /&gt;&lt;br /&gt;    public FluentHtmlCondition(bool fulfilled)&lt;br /&gt;    {&lt;br /&gt;        Fulfilled = fulfilled;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void Write(string output)&lt;br /&gt;    {&lt;br /&gt;        Output = output;&lt;br /&gt;    }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And in my Html-helper extension class i add&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public static IConditionWrite If(this HtmlHelper html, bool condition)&lt;br /&gt;{&lt;br /&gt;    return new ConditionBuilder().AddCondition(new FluentHtmlCondition(condition));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And there you have it all, hope someone can have some use with it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-9151393862730801972?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/9151393862730801972/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/02/meet-my-new-htmlhelper-extensions.html#comment-form' title='2 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/9151393862730801972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/9151393862730801972'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/02/meet-my-new-htmlhelper-extensions.html' title='Meet my new HtmlHelper extensions friends, ForEach and If'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-3296021111316919023</id><published>2010-02-02T10:04:00.003+01:00</published><updated>2010-02-02T10:12:56.437+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Repository'/><category scheme='http://www.blogger.com/atom/ns#' term='Domain Queries'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq'/><title type='text'>How I do data-access</title><content type='html'>Over the years I've tested alot of different techniques for getting data from a database in a .NET application.&lt;br /&gt;&lt;br /&gt;From the simple ADO.NET wrapper that executes raw sql or SP's and then returning a DataTable to the more specified "Repository" where each entity in my domain had a corresponding Repository for querying the data.&lt;br /&gt;&lt;br /&gt;I then discovered ORM's, especially NHibernate and started using it with the "One repository for each entity" approach. This worked great but when my projects grew bigger and bigger the need to create a new Repository for each new entity was to cumbersome (and often the Repository would have an interface, so for each new entity I created 3 new classes).&lt;br /&gt;&lt;br /&gt;I later implemented Linq2NHibernate and made it so that the most basic queries (i.e find by name, ordering etc) was made using it. More advanced queries I still shuffled into a entity-specific repository.&lt;br /&gt;&lt;br /&gt;My interface at this time looked at this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface INHibernateRepository&lt;br /&gt;{&lt;br /&gt;    ICriteria ExecuteCritera(DetachedCriteria criteria);&lt;br /&gt;    IQuery ExecuteCritera(string hql);&lt;br /&gt;    IList ExecuteMultiCriteria(params DetachedCriteria[] criterias);&lt;br /&gt;    void Delete&lt;entity&gt;(int id) where ENTITY : DomainObject;&lt;br /&gt;    int Save&lt;entity&gt;(ENTITY entity) where ENTITY : DomainObject;&lt;br /&gt;    IQueryable&lt;entity&gt; Query&lt;entity&gt;() where ENTITY : DomainObject; //Linq2Nhibernate&lt;br /&gt;    ENTITIY Get&lt;entitiy&gt;(int id) where ENTITIY : DomainObject;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pretty basic stuff for querying and fetching by Primary Key.&lt;br /&gt;&lt;br /&gt;If i got a entity specific repository i would extend INHibernateRepository like this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface QuestionRepository : INHibernateRepository&lt;br /&gt;{&lt;br /&gt;    Question GetLatestInserted();&lt;br /&gt;    //more question specific implementations&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I then, of course, had implementing classes of these interfaces.&lt;br /&gt;&lt;br /&gt;To use it in a MVC application I used Dependency Injection to wire up my controllers.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class QuestionController(INHibernateRepository repository, IQuestionRepository questionRepository, IUserRepository userRepository /* etc */)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Some may say that I shouldn't inject repositories directly to my controller, but even if I broke it out to a domain-service, it would still need 3 dependencies.&lt;br /&gt;&lt;br /&gt;So instead of using the approach above I have begun using Domain Queries. I've read abit about them before but I was when i read &lt;a href="http://www.lostechies.com/blogs/johnteague/archive/2010/01/30/implementing-domain-queries.aspx?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+LosTechies+%28LosTechies%29&amp;utm_content=Google+Reader"&gt;Implementing Domain Queries&lt;/a&gt; i realized how it would benefit me.&lt;br /&gt;&lt;br /&gt;I started my refactoring spree by adding two new methods on my repository interface&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface INHibernateRepository : IRepository&lt;br /&gt;{&lt;br /&gt;    IEnumerable&lt;t&gt; Query&lt;t&gt;(IDomainQuery&lt;t&gt; query);&lt;br /&gt;    T FindOne&lt;t&gt;(IDomainQuery&lt;t&gt; domainQuery);&lt;br /&gt;    /* All other methods */&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I then one by one extracted the more complicated queries to their own query-class.&lt;br /&gt;&lt;br /&gt;During this process I didn't encounter a single problem and I could remove all of my entity specific repositories and use _one_ repository for all database calls.&lt;br /&gt;&lt;br /&gt;So when I'm writing a query nowadays, I first and foremost try to use Linq, if that doesn't work I create a new query class instead of creating a whole new repository for a single entity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-3296021111316919023?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/3296021111316919023/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/02/how-i-do-data-access.html#comment-form' title='3 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/3296021111316919023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/3296021111316919023'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/02/how-i-do-data-access.html' title='How I do data-access'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-1645168668515398673</id><published>2010-01-29T11:44:00.011+01:00</published><updated>2010-02-02T10:06:32.758+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Template pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='Design patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>The template method pattern</title><content type='html'>One of my favorite patterns is the &lt;a href="http://en.wikipedia.org/wiki/Template_method_pattern"&gt;"Template method pattern"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Basically its about having a abstract class that defines common behaviour with points that can be customizable.&lt;br /&gt;&lt;br /&gt;Yesterday I was refactoring alot of classes tha't didn't make use of the template pattern, but they all inherited from the same base-class. The base-class acted more like a common place for methods that all objects needed.&lt;br /&gt;&lt;br /&gt;Let me show you some code that I had before the refactoring.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class QuestionQuery : QueryBuilder {&lt;br /&gt;&lt;br /&gt;public IFluentMdxQuery BuildQuery() {&lt;br /&gt;  return new FluentMdxQuery(_context)&lt;br /&gt;  .Get(x =&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    x.Rowset.ForQuestion(_queryId).WithChildren();&lt;br /&gt;    x.AddMeasure(DefaultMeasure.RespondentCount);&lt;br /&gt;    x.AddMeasure(DefaultMeasure.RespondentShare);&lt;br /&gt;&lt;br /&gt;    base.AddComparisonIndex(x);&lt;br /&gt;    base.AddBreakdown(x);&lt;br /&gt;    base.AddTimeBreak(x);&lt;br /&gt;    base.SwapAxes(x);&lt;br /&gt;  })&lt;br /&gt;  .WithFilter(base.FilterManager)&lt;br /&gt;  .Order.By(_properties.OrderBy)&lt;br /&gt;  .TheMeasureIs(currentMeasure)&lt;br /&gt;  .AscendingIf(_properties.OrderBy != OrderBy.Measure)&lt;br /&gt;  .SetupWith(setup =&amp;gt; {&lt;br /&gt;    setup.HideTheseIds(q =&amp;gt; q.AddRange(_properties.HiddenIds));&lt;br /&gt;    setup.AddHighlight.OnMeasure(DefaultMeasure.RespondentShare);&lt;br /&gt;  })&lt;br /&gt;  .WithRules(rules =&amp;gt; {&lt;br /&gt;    rules.AddDefaultRules(_properties.ShowAllAnswers());&lt;br /&gt;    foreach (var rule in base.AddedRules) {&lt;br /&gt;      rules.Add(rule);&lt;br /&gt;    }&lt;br /&gt;    rules.Add(new MakeQuestionLevelTotalAndPlaceLastRule());&lt;br /&gt;  });&lt;/pre&gt;&lt;br /&gt;Thats alot of base-method calls in there.&lt;br /&gt;Now take into consideration that I've got somewhere between 5 to 10 more classes like this.&lt;br /&gt;&lt;br /&gt;So yesterday I was assigned to add new functionality to the system which involved these classes. And because the classes are built as they are, I was forced to add the functionality to all classes, and that tingled my "bad code sense". I was duplicating code all over the place!&lt;br /&gt;&lt;br /&gt;So I sat down and realized that the Template method would be a perfect pattern to implement here. Make all common calls in a base-class and add ways of overriding the certain parts of the creation.&lt;br /&gt;&lt;br /&gt;So heres my new base class. (Some methods are missing since they not add any value besides of taking up space)&lt;br /&gt;&lt;pre&gt;public IFluentMdxQuery BuildQuery(ISetupFluentFilterManager filterQueryManager)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  return new FluentMdxQuery(_context)&lt;br /&gt;  .Get(x =&amp;gt; {&lt;br /&gt;    SetupDimensionCollector(x);&lt;br /&gt;    AddComparisonIndex(x);&lt;br /&gt;    AddBreakdown(x);&lt;br /&gt;    AddTimeBreak(x);&lt;br /&gt;    SwapAxes(x);&lt;br /&gt;  })&lt;br /&gt;  .WithFilter(AddFilter(filterQueryManager))&lt;br /&gt;  .SetupOrder(SetupOrder)&lt;br /&gt;  .SetupWith(AddSetupRules)&lt;br /&gt;  .WithRules(ruleCollector =&amp;gt; {&lt;br /&gt;    ruleCollector.AddDefaultRules();&lt;br /&gt;    foreach (var rule in _addedRules) {&lt;br /&gt;      ruleCollector.Add(rule);&lt;br /&gt;    }&lt;br /&gt;    AddExtraRules(ruleCollector);&lt;br /&gt;  });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;  protected abstract void SetupDimensionCollector(IDimensionCollector dimensionCollector)&lt;br /&gt;&lt;br /&gt;  protected virtual void SetupOrder(IFluentMdxSortCommand sortCommand)&lt;br /&gt;  {&lt;br /&gt;    sortCommand.UseDefault();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  protected virtual void AddExtraRules(IRuleCollector ruleCollector) { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Its almost looks the same as the old one, but this time I've added the metods to the base class, implemented the default behaviour and made them virtual so they can be overriden in the child classes. I also made some methods abstract to force the implementing classes to add them.&lt;br /&gt;&lt;br /&gt;So, how did these changes affect my QuestionQuery class?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;protected override void SetupDimensionCollector(IDimensionCollector dimensionCollector)&lt;br /&gt;{&lt;br /&gt;  dimensionCollector.Rowset.ForQuestion(_queryId).WithChildren();&lt;br /&gt;  dimensionCollector.AddMeasure(DefaultMeasure.RespondentCount);&lt;br /&gt;  dimensionCollector.AddMeasure(DefaultMeasure.RespondentShare);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected override void SetupOrder(IFluentMdxSortCommand sortCommand)&lt;br /&gt;{&lt;br /&gt;  sortCommand.By(_querySettings.OrderBy);&lt;br /&gt;  sortCommand.TheMeasureIs(GetCurrentMeasure());&lt;br /&gt;  sortCommand.AscendingIf(_querySettings.OrderBy != OrderBy.Measure);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Damn! Only 2 methods needed to be overriden. Everything else was default behaviour. Of course not all my classes we're as simple as this, but they all got more to the point and I avoided alot of duplication.&lt;br /&gt;&lt;br /&gt;These changes also make it easy for me to add functionality to all query classes easy, just add it to the base class and we're done :)&lt;br /&gt;&lt;br /&gt;&lt;a rev="vote-for" href="http://dotnetshoutout.com/kny-The-template-method-pattern"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fknysharp.blogspot.com%2F2010%2F01%2Ftemplate-method-pattern.html" style="border:0px"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-1645168668515398673?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/1645168668515398673/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/01/template-method-pattern.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/1645168668515398673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/1645168668515398673'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/01/template-method-pattern.html' title='The template method pattern'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-370773734675831070</id><published>2010-01-26T15:55:00.006+01:00</published><updated>2010-01-28T20:38:50.629+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Model binding'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>Model binding i .NET MVC</title><content type='html'>(From now on I will try to write my posts in english)&lt;br /&gt;I see alot of variations in how people do model-binding in .NET MVC.&lt;br /&gt;Some guys use the old-school way using &lt;span style="font-weight:bold;"&gt;Request.Form&lt;/span&gt; directly in their Controller actions.&lt;br /&gt;&lt;pre&gt;public ActionResult Create()&lt;br /&gt;{&lt;br /&gt;    Recipe recipe = new Recipe();&lt;br /&gt;    recipe.Name = Request.Form["Name"];&lt;br /&gt;    return View();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A better way is to pass a &lt;span style="font-weight:bold;"&gt;FormCollection&lt;/span&gt; to the action.&lt;br /&gt;&lt;pre class="csharpcode"&gt;public ActionResult Create(FormCollection values)&lt;br /&gt;{&lt;br /&gt;    Recipe recipe = new Recipe();&lt;br /&gt;    recipe.Name = values["Name"];      &lt;br /&gt;            &lt;br /&gt;    // ...&lt;br /&gt;            &lt;br /&gt;    return View();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The best way is of course to accept your entity directly.&lt;br /&gt;&lt;pre class="csharpcode"&gt;public ActionResult Create(Recipe recipe)&lt;br /&gt;{&lt;br /&gt;    _repository.Save(recipe);&lt;br /&gt;    return View();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This works great when dealing with simple objects.&lt;br /&gt;But what happens when you have a rich domain model and your entities references other entities and so on..&lt;br /&gt;&lt;br /&gt;Take this simple class for examle&lt;br /&gt;&lt;pre class="csharpcode"&gt;public class Comment&lt;br /&gt;{&lt;br /&gt; public int Id { get; set; }&lt;br /&gt; public string Message { get; set; }&lt;br /&gt; public Post Post { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If &lt;span style="font-style:italic;"&gt;Post&lt;/span&gt; is a reference to entity that's already saved in the database. How do you populate it nicely?&lt;br /&gt;Either you can let the ModelBinder bind what it can, and in your action method do&lt;br /&gt;&lt;pre class="csharpcode"&gt;public ActionResult Create(Comment comment)&lt;br /&gt;{&lt;br /&gt;    comment.Post = _repository.Load&lt;Post&gt;(Request.Post["PostId"]);&lt;br /&gt;    _repository.Save(comment);&lt;br /&gt;    return View();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This works, but I dont really like it :P&lt;br /&gt;&lt;br /&gt;I return to a solution further down.&lt;br /&gt;&lt;br /&gt;Another thing I often find irritating is the need to inject a repository into a controller only to read up a entity.&lt;br /&gt;Instead of having to do like this&lt;br /&gt;&lt;pre class="csharpcode"&gt;public class PostController : Controller&lt;br /&gt;{&lt;br /&gt;     private readonly IRepository _repository;&lt;br /&gt;     public PostController(IRepository repository)&lt;br /&gt;     {&lt;br /&gt;          _repository = repository;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public ViewResult Details(int id)&lt;br /&gt;     {&lt;br /&gt;          return View(_repository.Get&lt;Post&gt;(id));&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I would instead like it to be like this.&lt;br /&gt;&lt;pre class="csharpcode"&gt;public class PostController : Controller&lt;br /&gt;{&lt;br /&gt;     public ViewResult Details(Post post)&lt;br /&gt;     {&lt;br /&gt;          return View(post);&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now this was a very simple case, but even then i think it has several advantages, one being that it's easier to unit-test this method and another being that we can hide alot of repetetive code.&lt;br /&gt;&lt;br /&gt;How do I accomplish both binding to Details/Show-actions as well as binding more complex objects?&lt;br /&gt;&lt;br /&gt;Answer: I wrote my own modelbinder ;)&lt;br /&gt;&lt;pre class="csharpcode"&gt;public class GenericBinderResolver : DefaultModelBinder&lt;br /&gt;    {&lt;br /&gt;        private readonly ICanResolveDependencies _resolver;&lt;br /&gt;        private static readonly Type BinderType = typeof(IModelBinder&lt;&gt;);&lt;br /&gt;&lt;br /&gt;        private class ModelBindResult&lt;br /&gt;        {&lt;br /&gt;            public bool Success;&lt;br /&gt;            public object BoundObject;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// Creates a new GenericBinderResolver. This should be used as the DefaultModelBinder&lt;br /&gt;        /// &lt;/summary&gt;&lt;br /&gt;        /// &lt;param name="resolver"&gt;For easy testability of this class we created a new interface thats extracts out the "GetInstance" method from StructureMap.&lt;/param&gt;&lt;br /&gt;        public GenericBinderResolver(ICanResolveDependencies resolver)&lt;br /&gt;        {&lt;br /&gt;            _resolver = resolver;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)&lt;br /&gt;        {&lt;br /&gt;            //First look at the routes to see if we have any parameters named "Id", if we do load the entity from the database&lt;br /&gt;            var result = TryBindById(bindingContext, controllerContext);&lt;br /&gt;            if(result.Success) {&lt;br /&gt;                return result.BoundObject;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            //If there wasn't a Id in the route check if we have custom modelbinder for the type.&lt;br /&gt;            result = TryBindWithCustomModelBinder(bindingContext, controllerContext);&lt;br /&gt;            if (result.Success) {&lt;br /&gt;                return result.BoundObject;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            //If nothing works, do it the usual way.&lt;br /&gt;            return base.BindModel(controllerContext, bindingContext);&lt;br /&gt;        }&lt;br /&gt;  &lt;br /&gt;  private ModelBindResult TryBindById(ModelBindingContext bindingContext, ControllerContext controllerContext)&lt;br /&gt;        {&lt;br /&gt;            var result = new ModelBindResult();&lt;br /&gt;            &lt;br /&gt;            int entityId = 0;&lt;br /&gt;            //Is the type we're binding to assignable to our base domain object.&lt;br /&gt;            if (IsAssignableToDomainObject(bindingContext.ModelType))&lt;br /&gt;            {&lt;br /&gt;                if (EntityExistsInRoute(controllerContext.RouteData.Values, bindingContext.ModelName, out entityId))&lt;br /&gt;                {&lt;br /&gt;                    result.Success = true;&lt;br /&gt;     result.BoundObject = _resolver.TryGetInstance&lt;IRepository&gt;().Get(bindingContext.ModelType, entityId);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return result;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private ModelBindResult TryBindWithCustomModelBinder(ModelBindingContext bindingContext, ControllerContext controllerContext)&lt;br /&gt;        {&lt;br /&gt;            var result = new ModelBindResult();&lt;br /&gt;            Type genericBinderType = BinderType.MakeGenericType(bindingContext.ModelType);&lt;br /&gt;            IModelBinder binder = _resolver.TryGetInstance(genericBinderType) as IModelBinder;&lt;br /&gt;            if (binder != null) {&lt;br /&gt;                result.Success = true;&lt;br /&gt;                result.BoundObject = binder.BindModel(controllerContext, bindingContext);&lt;br /&gt;            }&lt;br /&gt;            return result;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private bool EntityExistsInRoute(RouteValueDictionary routeValueDictionary, string modelName, out int entityId)&lt;br /&gt;        {&lt;br /&gt;            entityId = TryParseRouteData(routeValueDictionary, "id");&lt;br /&gt;            if (entityId &gt; 0)&lt;br /&gt;                return true;&lt;br /&gt;&lt;br /&gt;            entityId = TryParseRouteData(routeValueDictionary, string.Concat(modelName, "id"));&lt;br /&gt;            if (entityId &gt; 0)&lt;br /&gt;                return true;&lt;br /&gt;&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private int TryParseRouteData(RouteValueDictionary routeValueDictionary, string key)&lt;br /&gt;        {&lt;br /&gt;            if (routeValueDictionary.ContainsKey(key))&lt;br /&gt;            {&lt;br /&gt;                string id = routeValueDictionary[key].ToString();&lt;br /&gt;                if (!string.IsNullOrEmpty(id))&lt;br /&gt;                {&lt;br /&gt;                    return int.Parse(id);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private bool IsAssignableToDomainObject(Type modelType)&lt;br /&gt;        {&lt;br /&gt;            return typeof(DomainObject).IsAssignableFrom(modelType);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Alot of code but the important things is that I inject a instance of ICanResolveDependencies which is a implementation of your favorite IoC-container. In my case StructureMap.&lt;br /&gt;&lt;br /&gt;I then look at the route data for a key named "id" if the ModelBindingContext.ModelType is a DomainObject which happens to be my base-class for all entites.&lt;br /&gt;So routes like "Post/Detail/5" would have a key named "id". I take the key and use it with to get the entity from the database. And whops i solved a problem.&lt;br /&gt;&lt;br /&gt;Also important to note is that if the ModelType isn't is a DomainObject nothing happens and I will let the default model-binder do its work.&lt;br /&gt;&lt;br /&gt;The next thing I do is to check if I have custom model-binder class for the ModelType. All my custom model-binders inherit from the same base-class which checks the Request.Form and Querystring dictionaries for a key named "id". If it finds a key named "id" and its greater than 0 it will call the abstract method "BindExisting(int originalId)" else it calls the abstract method "BindNew()".&lt;br /&gt;&lt;br /&gt;A implementation of a custom model-binder can look like this&lt;br /&gt;&lt;pre class="csharpcode"&gt;public class CommentBinder : ModelBinder&lt;Comment&gt;&lt;br /&gt;    {&lt;br /&gt;        private readonly INHibernateRepository _repository;&lt;br /&gt;  private readonly IUserContext _context;&lt;br /&gt;&lt;br /&gt;        public CommentBinder(INHibernateRepository repository, IUserContext context)&lt;br /&gt;        {&lt;br /&gt;            _repository = repository;&lt;br /&gt;   _context = context;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected override Comment BindNew()&lt;br /&gt;        {&lt;br /&gt;   //Don't do more work then necessary, I have method on the base-class which does the default model-binding.&lt;br /&gt;            var comment = base.DoDefaultModelBinding(); &lt;br /&gt;   &lt;br /&gt;   //Since I use NHibernate, just get a proxy to the Post and don't hit the database.&lt;br /&gt;   //The Get() method is within the base-class and just returns Request-data.&lt;br /&gt;            comment.Post = _repository.Load(Get("PostId")); &lt;br /&gt;   comment.User = _context.User;&lt;br /&gt;   &lt;br /&gt;   return comment;&lt;br /&gt;        }&lt;br /&gt;  &lt;br /&gt;  protected override Comment BindExisting(int entityId)&lt;br /&gt;        {&lt;br /&gt;            //load the entity and change the values&lt;br /&gt;   _repository.Get&lt;Comment&gt;(entityId);&lt;br /&gt;   &lt;br /&gt;            var comment = base.DoDefaultModelBinding(); &lt;br /&gt;   &lt;br /&gt;   comment.Post = _repository.Load(Get("PostId")); &lt;br /&gt;   comment.User = _context.User;&lt;br /&gt;   &lt;br /&gt;   return comment;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(I left out the code for the base class, if you want too see it email me kennyeliasson at gmail dot com)&lt;br /&gt;&lt;br /&gt;All I need to care about is how to handle existing and new objects.&lt;br /&gt;This solution have worked out really nice for me WHEN i have more complex objects. Of course I use the default model-binding as often as i can, but sometimes it just isn't enough.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-370773734675831070?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/370773734675831070/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/01/model-binding-i-net-mvc.html#comment-form' title='1 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/370773734675831070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/370773734675831070'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/01/model-binding-i-net-mvc.html' title='Model binding i .NET MVC'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-747078981246595967</id><published>2010-01-11T13:28:00.007+01:00</published><updated>2010-01-11T14:47:59.931+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Fluent NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Fluent NHibernate och automappa komponenter</title><content type='html'>Nu så vart man "äntligen" tillbaka på jobbet efter en skön jul och nyårsledighet.&lt;br /&gt;&lt;br /&gt;Det första jag tog tag i var att generera den nya tabeller till våran rapporteringsapplikation. Jag har tidigare  berättat om hur jag använder Fluent NHibernate för att göra detta, men denna gången störde jag mig mycket på att jag var tvungen att göra många mappningar "by-hand" via IAutoMappingOverride&lt;T&gt; för att jag skulle mappa Components.&lt;br /&gt;&lt;br /&gt;En Component är en egen klass men datan för klassen ligger i föräldrens tabell.&lt;br /&gt;T.ex. en MetaData-klass som innehåller Created, Version m.m.&lt;br /&gt;Denna MetaData-klass vill man inte mappa till en helt egen tabell utan man mappar min MetaData-klass till kolumner i dess föräldrer. I detta fall mappar jag min Report-entitet till en tabell med namnet Reports som även innehåller kolumner för MetaData-klassen.&lt;br /&gt;&lt;br /&gt;Problemet är ju att MetaData-klassen ligger som en property på Reports-klassen och därmed kommer mappas som en "one-to-many" referens. För att komma runt detta innan har jag ofta mappat komponenter för hand, men detta tröttnade jag på idag och bestämde mig för att se hur man kommer runt detta.&lt;br /&gt;&lt;br /&gt;Efter lite eftersökningar hittade jag hur säger vilka typer som skall hanteras som komponenter.&lt;br /&gt;&lt;br /&gt;På Fluent Nhibernates AutoPersistanceModel finns det en metod som heter Setup(). Via denna kan man bestämma vilka klasser som skall hanteras som komponenter.&lt;br /&gt;&lt;br /&gt;.Setup(s =&gt; { s.IsComponentType = type =&gt; typeof (MetaData) })&lt;br /&gt;&lt;br /&gt;Nu fick jag MetaData-klassen att vara mappad som en komponent. Men hur jag gör om så att alla mina befintliga komponenter mappas in på samma sätt?&lt;br /&gt;&lt;br /&gt;.Setup(s =&gt; { s.IsComponentType = type =&gt; typeof (MetaData) || type =&gt; typeof(Component2) || etc.. etc.. })&lt;br /&gt;&lt;br /&gt;Att göra som ovan med flera "eller" alternativ kan ju bli lite grötigt.&lt;br /&gt;&lt;br /&gt;Det jag gjorde istället var att jag gjorde ett tomt interface, ett så kallat marker-interface&lt;br /&gt;&lt;br /&gt;public interface IComponent { }&lt;br /&gt;&lt;br /&gt;och gjorde så att alla mina komponent-klasser ärvde av det. Sen ändrade jag Setup-koden till&lt;br /&gt;&lt;br /&gt;.Setup(s =&gt; { s.IsComponentType = type =&gt; typeof (IComponent).IsAssignableFrom(type) })&lt;br /&gt;&lt;br /&gt;Detta jag tycker jag är sjukt smidigt :) &lt;br /&gt;&lt;br /&gt;Om man inte vill använda marker interfaces kan man ju t.ex. använda sig av attribut men då måste man använda reflection för att läsa av klasserna.&lt;br /&gt;&lt;br /&gt;Vad tycker ni, vettig lösning? Vad tycker ni om Marker-interfaces vs. Attribut?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-747078981246595967?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/747078981246595967/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/01/fluent-nhibernate-och-automappa.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/747078981246595967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/747078981246595967'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/01/fluent-nhibernate-och-automappa.html' title='Fluent NHibernate och automappa komponenter'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-3573786055123594656</id><published>2010-01-05T12:20:00.004+01:00</published><updated>2010-01-05T13:40:00.049+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='problem'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Django, perfect fit</title><content type='html'>Har under min vintersemester haft möjligheten att fördjupa mig i Django.&lt;br /&gt;&lt;br /&gt;Det enda jag gjort i Django tidigare är ett par väldigt lätta exempel som jag visat upp för kompisar men nu skulle jag göra ett riktigt projekt, om än väldigt litet.&lt;br /&gt;&lt;br /&gt;Sidan jag skapar är en personlig hemsida till en släkting och det enda som behövs är ett nyhetsarkiv och ett bildgalleri, allt annat kan vara statiskt till en början då hemsidan inte är tänkt att uppdateras allt för ofta.&lt;br /&gt;&lt;br /&gt;Så jag satte igång med att generera mina modeller, admin-gränssnittet ändrade inställningar för språk och databaser tills jag stötte på mitt första problem, inlänkning av stylesheets, javascript och bilder.&lt;br /&gt;&lt;br /&gt;Först trodde jag att det hade med mina urls, att jag skulle mappa "media"-filer rätt, men det funkade inte! Efter att ha gjort en snabb google-sökning så visade det sig att man skulle använda sig av en inställning som heter MEDIA-ROOT.&lt;br /&gt;Som tur är har vi ett Django projekt på jobbet, så jag drog helt sonika hem det för att se hur dom hade löst det.&lt;br /&gt;&lt;br /&gt;if LIVE:&lt;br /&gt;    SITE_URL = 'http://www.skarp_hemsida.se'&lt;br /&gt;else:&lt;br /&gt;    SITE_URL = 'http://localhost:8000'&lt;br /&gt; &lt;br /&gt;DJANGO_ROOT = os.path.dirname(os.path.realpath(django.__file__)).replace("\\", "/")&lt;br /&gt;SITE_ROOT = os.path.dirname(os.path.realpath(__file__)).replace("\\", "/")&lt;br /&gt;MEDIA_ROOT = SITE_ROOT + '/m/'&lt;br /&gt;MEDIA_URL = SITE_URL + '/m/'&lt;br /&gt;ADMIN_MEDIA_PREFIX = '/media/'&lt;br /&gt;&lt;br /&gt;En alldeles utmärkt lösning som funkar live och lokalt. Nu var det bara att länka in stylesheetsen med "/m/css/xxx.css"&lt;br /&gt;&lt;br /&gt;Andra problem som jag stötte på är att alltid glömma ":" efter class och for-loop deklarationer (class MyClass: resp. for i in ints:).&lt;br /&gt;Att kopiera kod från andra dokument eller ifrån webben förstör verkligen tab-indentering och får Python att fräsa ur sig felmeddelanden.&lt;br /&gt;&lt;br /&gt;Saker som jag verkligen avundar folk som sitter och jobbar med Django är template-systemet. Jag som kommer ifrån .NET med sina fula &lt;% %&gt; taggar och for/if-satser avundas verkligen {% %} syntaxen och alla hjälp-metoder som finns.&lt;br /&gt;&lt;br /&gt;ActiveRecord, dvs databashantering, spara, querya etc är nåt som funkar out-of-the-box och inget man tänker över. Skönt att slippa behöva skriva kod för att få detta att funka.&lt;br /&gt;&lt;br /&gt;PIL, Python Image Library, har jag jobbat en del med för att förminska bilder. Av det lilla jag jobbat med det har det varit helt underbart, man märker att utvecklarna bakom har tagit ett steg till och tänkt till hur vi som utnyttjar API:et vill använda det, inte hur man proppar det med fullt "low-level" funktioner som t.ex. .NET's System.Drawing.&lt;br /&gt;&lt;br /&gt;Det har varit mycket lärorikt att sitta och jobba med ett helt annat språk ett tag, ett dynamiskt språk har verkligen sina fördelar men även nackdelar, men mycket av nackdelarna just nu är antagligen för att jag inte har 100% koll på Python.&lt;br /&gt;&lt;br /&gt;Någon av er andra som testat ett par andra språk? Ruby har det ju varit mycket snack om men jag har inte riktigt gillat syntaxen. Kanske nåt funktionellt, F#, Lisp, Haskell? Skriv gärna en kommentar :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-3573786055123594656?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/3573786055123594656/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2010/01/django-perfect-fit.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/3573786055123594656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/3573786055123594656'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2010/01/django-perfect-fit.html' title='Django, perfect fit'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-8634978186198230874</id><published>2009-12-11T09:00:00.005+01:00</published><updated>2009-12-11T10:57:26.495+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hobbyprojekt'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='hobby'/><category scheme='http://www.blogger.com/atom/ns#' term='projektstruktur'/><category scheme='http://www.blogger.com/atom/ns#' term='framtid'/><title type='text'>Hobbyprojekt, förr, nu och i framtiden.</title><content type='html'>Efter att ha startat och lagt ner ett flertal hobbyprojekt så börjar nu lusten att starta upp nåt nytt att leka med på fritiden komma tillbaka.&lt;br /&gt;&lt;br /&gt;Efter att ha startat upp en budget-site, en e-shop lösning till min pappa och massa annat småpill utan att komma i mål med nåt av projekten så känns det nästan lite dödsdömt från början. Jag undrar varför det blir så? Varför kan jag inte slutföra mina hobbyprojekt?&lt;br /&gt;&lt;br /&gt;Dels är det såklart tidsaspekten, jag orkar helt enkelt inte sätta mig vid datorn och fortsätta programmera när jag kommer hem. Som tur är har jag ett jobb där jag har möjlighet att utforska nya grejer på arbetstid. Samtidigt missar jag ju tekniker som jag inte jobbar med på jobbet, och om vi då bara snackar om .NET stacken så missar jag t.ex. Silverlight och WCF . Python och Ruby skulle vara oerhört intressant att lära sig mer om även om jag får sitta med Python ibland så vill jag gärna sitta mer med det för att komma in i det "dynamiska tänket"&lt;br /&gt;&lt;br /&gt;Men de hobbyprojekt som jag ändå drar igång har en tydlig tendens att dö ut när jag kommer till design-biten. Jag är inte världens bästa designer och tröttnar lätt på nåt jag knåpat ihop själv, vilket får mig att tappa intresset för hela projektet.&lt;br /&gt;&lt;br /&gt;Med denna kunskap i bagaget kanske man skulle ge sig på att bygga nåt utan ett alltför grafiskt gränssnitt.&lt;br /&gt;&lt;br /&gt;Idag hade jag tänkt mig att bygga en "Nytt projekt mappstruktur" så att man slipper skapa mappar för lib, src, doc och att den automatiskt skapar en solution fil. Och allt detta ska skötas ifrån consolen :)&lt;br /&gt;&lt;br /&gt;En annan tanke är att skapa ett väldigt lätt ramverk ovanpå .NET MVC. Det jag vill uppfylla är nåt liknande Django där modellerna och admingränssnitt autogenereras, samt att mycket av de kommandon man kör i Python-consolen har sina motsvarigheter i mitt proejkt (t.ex. startproject, syncdb etc). Alltså nåt som man lätt kommer igång med.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-8634978186198230874?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/8634978186198230874/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2009/12/hobbyprojekt-forr-nu-och-i-framtiden.html#comment-form' title='3 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/8634978186198230874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/8634978186198230874'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2009/12/hobbyprojekt-forr-nu-och-i-framtiden.html' title='Hobbyprojekt, förr, nu och i framtiden.'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-4182730627668486649</id><published>2009-12-09T09:30:00.000+01:00</published><updated>2009-12-09T09:37:10.937+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VM'/><category scheme='http://www.blogger.com/atom/ns#' term='virtuellt'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='VMWare'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>VMWare player och mig</title><content type='html'>Satt och kikade på Tekpubs senaste avsnitt om NHibernate när jag kikade på vidare på vad de erbjöd för mer videos. Hittade då en om Linux och Ruby on Rails och i den visade dom hur man installerar Ubuntu på en virtuell maskin.&lt;br /&gt;&lt;br /&gt;Och eftersom jag aldrig använt virtuella maskiner innan så tänkte jag att nu var det dags. Så sagt och gjort gick hem installerade VMWare player och laddade hem nyaste Ubuntu. &lt;br /&gt;&lt;br /&gt;Installationen gick hur smidigt som helst och tog inte mer än 10 minuter innan jag var inne i operativet och började utforska Linux igen. Sist var nog för 5 år sedan och då körde jag Slackware. Och jisses sicken skillnad på operativ då och nu, kan absolut se mig gå över till en dist av Linux i framtiden. Synd bara att Visual Studio och C# inte finns fullt implementerat.&lt;br /&gt;&lt;br /&gt;Saker man direkt faller "in love" med är apt-get för att hämta hem t.ex. Ruby och Django med alla dependencies. Så allt installeras utan att du behöver tänka på nåt. Sen är det skönt att ha en vettig terminal, det är trots allt lite "h4xX0r" känsla på det :)&lt;br /&gt;&lt;br /&gt;Man får kanske installera VMWare och köra Windows virtuellt så att man kan fortsätta programmera på .NET plattformen? :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-4182730627668486649?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/4182730627668486649/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2009/12/vmware-player-och-mig.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/4182730627668486649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/4182730627668486649'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2009/12/vmware-player-och-mig.html' title='VMWare player och mig'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-4338104530940513164</id><published>2009-12-02T08:45:00.000+01:00</published><updated>2009-12-02T13:15:17.251+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Conventions'/><category scheme='http://www.blogger.com/atom/ns#' term='Mappning'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Fluent NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Databas'/><title type='text'>Migrering till Fluent NHibernate</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Läste &lt;a style="font-family: trebuchet ms;" href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/12/01/migrating-to-fluent-nhibernate.aspx?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+LosTechies+%28LosTechies%29&amp;amp;utm_content=Google+Reader"&gt;Jimmy Bogards blog-post&lt;/a&gt; angående migrering till Fluent NHibernate och tänkte beskriva hur vi gick till väga när vi tog steget från hbm-mappningsfiler till Fluent NHibernate.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Till att börja med, varför gjorde vi switchen ifrån fungerande mappnings-filer till Fluent Nhibernate? Om vi inte skulle använda auto-mappning så är det enda vi gör att flytta mappningen ifrån xml-filer till cs-filer. Visst vi tjänar type-safety men med ReSharper så är det oftast inget problem med att mappa via Xml.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Så det vi ville åt var auto-mappningen! Och då projektet vi jobbar på är hyffsat Greenfield (vart igång i ett år nu, och redan hunnit med att byggas om ifrån ett egenutvecklad MVP-ramverk uppepå WebForms till att nu vara byggt i MVC (en helt annan blog-post ;) ) så är även databasen Greenfield.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;En snabb check på databasens tabeller och kolumner visade att vi använder rätt enkla conventions som man kan implementera. T.ex. är alla tabeller i plural, dvs med ett "s". Våra Foreign-keys slutar på dessutom på ID.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Att implementera dessa conventions i Fluent NHibernate var lätt.&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ReportalMappingConventions : IReferenceConvention, IHasManyConvention, IClassConvention, IJoinedSubclassConvention, IIdConvention&lt;br /&gt;  {&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(IManyToOneInstance instance)&lt;br /&gt;      {&lt;br /&gt;          instance.Column(instance.Property.Name + &lt;span class="str"&gt;"ID"&lt;/span&gt;);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(IOneToManyCollectionInstance instance)&lt;br /&gt;      {&lt;br /&gt;          instance.Key.Column(instance.EntityType.Name + &lt;span class="str"&gt;"ID"&lt;/span&gt;);&lt;br /&gt;          instance.LazyLoad();&lt;br /&gt;          instance.Inverse();&lt;br /&gt;          instance.Cascade.SaveUpdate();&lt;br /&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt; ((&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(INotCacheable).IsAssignableFrom(instance.Relationship.Class.GetUnderlyingSystemType())))&lt;br /&gt;              &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;          instance.Cache.ReadWrite();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(IClassInstance instance)&lt;br /&gt;      {&lt;br /&gt;          instance.Table(instance.EntityType.Name + &lt;span class="str"&gt;"s"&lt;/span&gt;);&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt; ((&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(INotCacheable).IsAssignableFrom(instance.EntityType)))&lt;br /&gt;              &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;          instance.Cache.ReadWrite();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(IJoinedSubclassInstance instance)&lt;br /&gt;      {&lt;br /&gt;          &lt;span class="rem"&gt;//Fixa detta mer generiskt?&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;if&lt;/span&gt;(instance.EntityType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ClusterAnswerOption)) {&lt;br /&gt;              instance.Table(&lt;span class="str"&gt;"ClusterOptionFilter"&lt;/span&gt;); &lt;span class="rem"&gt;//TODO: Denna tabellen borde inte heta så här FÖLJ CONVENTIONS!&lt;/span&gt;&lt;br /&gt;              instance.Key.Column(instance.EntityType.BaseType.Name + &lt;span class="str"&gt;"ID"&lt;/span&gt;);&lt;br /&gt;          } &lt;span class="kwrd"&gt;else&lt;/span&gt; {&lt;br /&gt;              instance.Key.Column(instance.EntityType.BaseType.Name + &lt;span class="str"&gt;"ID"&lt;/span&gt;);&lt;br /&gt;              instance.Table(instance.EntityType.Name + &lt;span class="str"&gt;"s"&lt;/span&gt;);&lt;br /&gt;              &lt;span class="rem"&gt;//instance.Key.Column(instance.EntityType.Name + "ID");&lt;/span&gt;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(IIdentityInstance instance)&lt;br /&gt;      {&lt;br /&gt;          instance.UnsavedValue(&lt;span class="str"&gt;"0"&lt;/span&gt;);&lt;br /&gt;      }&lt;br /&gt;  }&lt;/pre&gt;&lt;span style="font-family:trebuchet ms;"&gt;Som ni ser är det vi gör att lägga till ID samt "pluralisera" tabellnamnen. Vi använder oss också utav ett Marker-interface på våra entiter kallat INotCacheable för att bestämma om entiter skall använda sig utav NHibernates 2nd level-cache eller inte.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Såklart finns det tillfällen då automappningen inte räcker till eller då man tyvärr byggt tabeller och/eller kolumner med felnamn och måste mappa detta manuellt. På de allra flesta av våra entiter räcker det att implementera IAutoMappingOverride&lt;/span&gt;&lt;t  style="font-family:trebuchet ms;"&gt; som nedan&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ProjectMap : IAutoMappingOverride&amp;lt;Project&amp;gt;&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Override(AutoMapping&amp;lt;Project&amp;gt; mapping)&lt;br /&gt; {&lt;br /&gt;    mapping.HasMany(x =&amp;gt; x.ResultSources).Access.CamelCaseField(Prefix.Underscore).Cascade.AllDeleteOrphan();&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;project&gt;&lt;project&gt;&lt;br /&gt;Nu skriver vi bara över ResultSources propertyn och låter Fluent NHibernate mappa resten.&lt;br /&gt;&lt;br /&gt;Detta funkar kanon och jag har inte ångrat mig en dag att vi migrerade.&lt;br /&gt;&lt;br /&gt;Den absolut största fördelen med migrering är såklart att alla nya entiter man skapar är mappade från början så länge de ärver från våran "bas-entitet". Och det som är underbart med är att man slipper skapa databasen själv, utan tar schemat som NHibernate spottar ut och kör på databasen, och voíla, nya tabeller genererade! Ett annat plus är ju att tabellerna skapas utifrån projektets conventions och man då inte i första taget går runt dem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;(Ser även att jag behöver nåt för att göra kod snyggare, nån som har nåt tips?)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/project&gt;&lt;/project&gt;&lt;/t&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-4338104530940513164?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/4338104530940513164/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2009/12/migrering-till-fluent-nhibernate.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/4338104530940513164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/4338104530940513164'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2009/12/migrering-till-fluent-nhibernate.html' title='Migrering till Fluent NHibernate'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8627092016055243145.post-6468141810810833441</id><published>2009-11-25T08:56:00.000+01:00</published><updated>2009-11-25T14:14:39.689+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Criteria'/><category scheme='http://www.blogger.com/atom/ns#' term='Repository'/><category scheme='http://www.blogger.com/atom/ns#' term='Interfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Get'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Load'/><title type='text'>NHibernate, skillnader mellan Load, Get och Criteria</title><content type='html'>Stötte på ett konstigt problem häromdagen när jag satt och refaktorerade data-access kod via NHibernate till ett av de första projekten där vi använde det. Problemet som skulle lösas var att ConnectionStrings var hårdkodade i vårt hemgjorda assembly.&lt;br /&gt;&lt;br /&gt;För att lösa problemet använde jag kod från ett nyare projekt.&lt;br /&gt;&lt;br /&gt;I projekten har vi ett Bas-repository som vi använder oss utav och när jag satt och kikade på skillnaderna såg att GetById() metoden skiljde sig åt i de båda klasserna.&lt;br /&gt;&lt;br /&gt;I den gamla klassen anropades Session.CreateCriteria() istället för det Load() eller Get() som man kanske hade kunnat förutspå.&lt;br /&gt;&lt;br /&gt;Skillnaderna mellan Criteria, Get och Load som jag fattat det är att&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Load()&lt;/b&gt;&lt;br /&gt;Hämtar aldrig ifrån databasen utan returnerar bara en proxy. Det vill säga, använder du Load() med ett ID som inte finns i databasen kommer du inte få ett fel förrens du försöker komma åt objektets egenskaper. Denna lösningen är den att rekommendera när du vill koppla på referenser till t.ex. nya skapade objekt men inte vill ladda upp alla dessa referenser bara för att kunna spara det nya objektet.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Get&lt;/b&gt;&lt;br /&gt;Samma som Load() men kommer att gå till databasen/cachen för att veta att ID:et verkligen finns.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;CreateCriteria&lt;/b&gt;&lt;br /&gt;CreateCriteria är lite svårare, kommer man ifrån en värld där man är van att skriva Sql själv så tänker man ju förstås att det måste vara den korrekta vägen att gå. Men CreateCriteria hoppar över cachen (om inte specifierat annorlunda) och objektet man får tillbaka cachas inte.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Källa&lt;/b&gt;&lt;br /&gt;Läs mer här &lt;a href="http://ayende.com/Blog/archive/2009/04/30/nhibernate-ndash-the-difference-between-get-load-and-querying-by.aspx"&gt;Ayende om Load, Get och Query By Id&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Jag tänkte inte särskilt mycket mer på att vi använde CreateCriteria utan bytte helt sonika ut den mot en Load. Efter mycket pill så hade jag lyckats byta ut den gamla implementation mot den nya.&lt;br /&gt;&lt;br /&gt;Tryckte på F5 och körde igång projektet. Och till min stora förvåning funkade allt perfekt, ett tag iallafall. Helt plötsligt fick jag ett exception ifrån NHibernate.&lt;br /&gt;&lt;br /&gt;(No persister exists for QS.Product.Core.Interfaces.ICustomer)&lt;br /&gt;&lt;br /&gt;Nu tänker man såklart, detta kanske har med att jag glömt embedda en mapping fil, men si, så lätt var det inte. Jag gick till mappningen och kollade, såg att vi mappade till klassen som interfacet implementerade och använde interfacet som proxy-klass.&lt;br /&gt;&lt;br /&gt;Koden i som kastade felet såg ut så här:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;_session.Load&amp;lt;ICustomer&amp;gt;(531);&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Med tanke på felmeddelandet så måste ju detta betyda att ICustomer inte var mappad, vilket den ju inte heller var, det var ju implementation av Interfacet som var mappat. Men hur kunde det funkat innan? Jag bytte ju bara ut bas-repositoriet, inte alla repositoryn som användes, inte heller ändrade jag configuration eller mappningen.&lt;br /&gt;&lt;br /&gt;Problemet låg i att CreateCriteria&lt;ICustomer&gt;() kan hantera detta, varför, det vet jag inte :)&lt;br /&gt;&lt;br /&gt;Men lösningen för mig var att typa om alla mina repositories till att använda klassen istället för interfacet.&lt;br /&gt;&lt;br /&gt;Det vore intressant att veta varför CreateCriteria funkar men inte Load/Get :)&lt;br /&gt;&lt;br /&gt;Detta blev ett långt första inlägg, får hålla mig lite kortare i framtiden.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8627092016055243145-6468141810810833441?l=knysharp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://knysharp.blogspot.com/feeds/6468141810810833441/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://knysharp.blogspot.com/2009/11/nhibernate-skillnader-mellan-post-get.html#comment-form' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/6468141810810833441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8627092016055243145/posts/default/6468141810810833441'/><link rel='alternate' type='text/html' href='http://knysharp.blogspot.com/2009/11/nhibernate-skillnader-mellan-post-get.html' title='NHibernate, skillnader mellan Load, Get och Criteria'/><author><name>Kenny Eliasson</name><uri>http://www.blogger.com/profile/11527412102990186115</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
