Support multiple service models for a component. WindsorServiceHostFactory will...
[castle.git] / MonoRail / Castle.MonoRail.ActiveRecordSupport / ARFetcher.cs
blobfc2de06dd0e53b75b326cd3449000ab6fab0502a
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MonoRail.ActiveRecordSupport
17 using System;
18 using System.Reflection;
20 using NHibernate;
21 using NHibernate.Criterion;
23 using Castle.ActiveRecord;
24 using Castle.ActiveRecord.Framework.Internal;
25 using Castle.Components.Binder;
26 using Castle.MonoRail.Framework;
28 /// <summary>
29 /// Class responsible on loading records for parameters marked with the <see cref="ARFetchAttribute" />.
30 /// </summary>
31 public class ARFetcher
33 private readonly IConverter converter;
35 public ARFetcher(IConverter converter)
37 this.converter = converter;
40 public object FetchActiveRecord(ParameterInfo param, ARFetchAttribute attr, IRequest request)
42 Type type = param.ParameterType;
44 bool isArray = type.IsArray;
46 if (isArray) type = type.GetElementType();
48 ActiveRecordModel model = ActiveRecordModel.GetModel(type);
50 if (model == null)
52 throw new MonoRailException(String.Format("'{0}' is not an ActiveRecord " +
53 "class. It could not be bound to an [ARFetch] attribute.", type.Name));
56 if (model.CompositeKey != null)
58 throw new MonoRailException("ARFetch only supports single-attribute primary keys");
61 String webParamName = attr.RequestParameterName != null ? attr.RequestParameterName : param.Name;
63 if (!isArray)
65 return LoadActiveRecord(type, request.Params[webParamName], attr, model);
68 object[] pks = request.Params.GetValues(webParamName);
70 if (pks == null)
72 pks = new object[0];
75 Array objs = Array.CreateInstance(type, pks.Length);
77 for(int i = 0; i < objs.Length; i++)
79 objs.SetValue(LoadActiveRecord(type, pks[i], attr, model), i);
82 return objs;
85 private object LoadActiveRecord(Type type, object pk, ARFetchAttribute attr, ActiveRecordModel model)
87 object instance = null;
89 if (pk != null && !String.Empty.Equals(pk))
91 PrimaryKeyModel pkModel = ObtainPrimaryKey(model);
93 Type pkType = pkModel.Property.PropertyType;
95 bool conversionSucceeded;
96 object convertedPk = converter.Convert(pkType, pk.GetType(), pk, out conversionSucceeded);
98 if (!conversionSucceeded)
100 throw new MonoRailException("ARFetcher could not convert PK {0} to type {1}", pk, pkType);
103 if (attr.Eager == null || attr.Eager.Length == 0)
105 // simple load
106 instance = ActiveRecordMediator.FindByPrimaryKey(type, convertedPk, attr.Required);
108 else
110 // load using eager fetching of lazy collections
111 DetachedCriteria criteria = DetachedCriteria.For(type);
112 criteria.Add(Expression.Eq(pkModel.Property.Name, convertedPk));
113 foreach (string associationToEagerFetch in attr.Eager.Split(','))
115 string clean = associationToEagerFetch.Trim();
116 if (clean.Length == 0)
118 continue;
121 criteria.SetFetchMode(clean, FetchMode.Eager);
124 object[] result = (object[]) ActiveRecordMediator.FindAll(type, criteria);
125 if (result.Length > 0)
126 instance = result[0];
130 if (instance == null && attr.Create)
132 instance = Activator.CreateInstance(type);
135 return instance;
138 private static PrimaryKeyModel ObtainPrimaryKey(ActiveRecordModel model)
140 if (model.IsJoinedSubClass || model.IsDiscriminatorSubClass)
142 return ObtainPrimaryKey(model.Parent);
144 return model.PrimaryKey;