ibatis-user-cs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Alexandre Grenier" <Alexandre.Gren...@markettools.com>
Subject RE: Latest nightly build and existing List-based Generics calls result in ambiguous method
Date Thu, 18 May 2006 16:40:48 GMT
Hi Chris

 

Personally I prefer to not use the overload that has a result object
parameter. As well, I like clearly seeing that the mapper method called
is a generic implementation. Surely some code will break when switching
from the 1.1 to the 2.0 binary. I am expecting more breakage before the
official release, and future releases as well. The code posted below is
problematic primarily because of the direct coupling between IBatis and
your domain objects.

 

To help have a handle on that I am limiting the coupling to IBatis
within a single static Mapper class in the Infrastructure layer. The
IBatis calls are wrapped like this:

 

    using IBatis = IBatisNet.DataMapper;

    public static class Mapper

    {

        private static IBatis.SqlMapper mapper =
IBatis.Mapper.Instance();

 

        public static Object Create(String statement, Object parameters)

        {

            return mapper.Insert(statement, parameters);

        }

 

        public static T Retrieve<T>(String statement, Object parameters)

        {

            return mapper.QueryForObject<T>(statement, parameters);

        }

 

        public static IList<T> RetrieveList<T>(String statement, Object
parameters)

        {

            return mapper.QueryForList<T>(statement, parameters);

        }

 

        [. . .]

    }

 

To keep the Domain layer segregated from the data mapping context, the
logic is wrapped within an abstract Repository class in the
Infrastructure layer, like this:

 

    public abstract class Repository<T> : IStaticable

    {

        private string name;

 

        public Repository(string name)

        {

            this.name = name;

        }

 

        public Object Add(T entity)

        {

            return Mapper.Create(name + "Create", entity);

        }

 

        public List<T> Find(T entity)

        {

            return Mapper.RetrieveList<T>(name + "Retrieve", entity) as
List<T>;

        }

 

        [. . .]

    }

            

Then for each root domain entity I implement repositories in my Domain
layer like this:

 

    internal class AccountRepository : Repository<Account>

    {

        public AccountRepository() : base("Account") { }

    }

 

    internal class FilterRepository : Repository<Filter>

    {

        public FilterRepository() : base("Filter") { }

 

        // Facilitation methods

 

        internal Filter RetrieveByFilterId(Int32 id)

        {

            Filter filter = new Filter();

            filter.Id = id;

            return Find(filter)[0];

        }

 

        internal List<Filter> RetrieveByDocumentId(Int32 id)

        {

            Filter filter = new Filter();

            filter.DocumentId = id;

            return Find(filter);

        }

    }

 

Then all Repositories are grouped in a factory, in Domain layer:

 

    internal class Repositories : StaticFactory

    {

        internal static AccountRepository Account

        {

            get { return Get<AccountRepository>(); }

        }

 

        internal static FilterRepository Filter

        {

            get { return Get<FilterRepository>(); }

        }

 

        [. . .]

    }

 

In Infrastructure layer:

 

    public abstract class StaticFactory

    {

        protected static T Get<T>()

            where T : IStaticable, new()

        {

            // Static is my implementation of a generic type singleton

            return Static<T>.Instance;

        }

    }

 

This way developers working in the Application layer can discover the
domain using intellisense and Repositories. I.E. List<Account> =
Repositories.Account.Find(account); My IBatis SqlMap files are
configured to retrieve entities as fully formed aggregates / object
graphs. For complex objects it results in A LOT of commands, but I am
hoping that a good cache system and future releases of IBatis with
GroupBy and generic proxies makes this a viable design.

 

The main point is to isolate coupling with IBatis within a single class.
The two benefits are that breaking changes in future IBatis releases
will be easy to deal with, and that Mapper can eventually implement the
Strategy pattern if I need to obtain domain objects from other sources
(web services come to mind), while keeping the domain completely
ignorant of this.

 

I hope this demonstrates my reasoning that it is important to have a
clear distinction between a generic and typed implementation.

 

Alex

 

 

________________________________

From: Christopher Bissell [mailto:chris@enhypniomancy.com] 
Sent: Thursday, May 18, 2006 3:47 AM
To: user-cs@ibatis.apache.org
Subject: Latest nightly build and existing List-based Generics calls
result in ambiguous method

 

Hey folks,

 

One of the cool things about IBatis was that the below code actually
worked when running the 1.1 codebase in the 2.0 Framework:

 

       List<DoNotMail> items = new List<DoNotMail>();

       mapper.QueryForList("GetDoNotMail_Check", email, items);

 

The thing is, the above code pattern, while perfectly legal, will result
in a compile error in the current 2005 sourcetree:

 

Error     317       The call is ambiguous between the following methods
or properties: 'IBatisNet.DataMapper.SqlMapper.QueryForList(string,
object, System.Collections.IList)' and
'IBatisNet.DataMapper.SqlMapper.QueryForList<MySpace.Domain.Media.Song>(
string, object,
System.Collections.Generic.IList<MySpace.Domain.Media.Song>)'

 

The reason for this is that the 1st method technically accepts an IList,
and a generic List still implements IList.  So IList and IList<T> are
not mutually exclusive.  

 

While the above code would compile fine if the second line were
re-written as:

 

       sql.QueryForList<Song>("GetBandSongList", bandID, songList);

                     

it makes me wonder if this kind of pattern (differentiating between
generic lists and lists - when they both implement IList) will result in
more of these types of logical issues?

 

Thoughts?

 

Chris

 

 


Mime
View raw message