Jeff-Lewis / codesmith

Automatically exported from code.google.com/p/codesmith
0 stars 0 forks source link

CSLA Many-To-Many Support #150

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Need to get samples implementations before reimplementing.

Original issue reported on code.google.com by bniemyjski on 5 Oct 2009 at 12:38

GoogleCodeExporter commented 9 years ago
A sample was sent to me. I will be reviewing this sample and adding many to many
support back into the templates.

Original comment by bniemyjski on 20 Nov 2009 at 6:21

GoogleCodeExporter commented 9 years ago
Currently any relationship tagged as ManyToMany does not get processed at all.  
Until 
ManyToMany support gets back in it would be better to ignore the ManyToMany tag 
and 
process it like a normal OneToMany and ManyToOne.  

Note also there is no warning message.  The relationship property simply 
doesn't get 
rendered by properties.cst causing some confusion.  

Given the constraints what defines a ManyToMany relationship, it's trivial to 
work 
around it by changing the N-N table but that's not the point. 

// 1) Table must have Two ForeignKeys.
// 2) All columns must be either...
//    a) Member of the Primary Key.
//    b) Member of a Foreign Key.
//    c) A DateTime stamp (CreateDate, EditDate, etc).
//    d) Name matches Version Regex.

Do you want another sample? I've patched it locally in Entity.cs by removing 
the 
IsManyToMany check.

Original comment by Batku...@gmail.com on 14 May 2010 at 11:49

GoogleCodeExporter commented 9 years ago
Hello,

I do have a patch for manyTomany support that I need to review and get it 
committed. I do tend to agree with you that maybe these should be treated as a 
OneToMany and ManyToOne

Thanks
-Blake Niemyjski

Original comment by bniemyjski on 19 Jun 2010 at 9:16

GoogleCodeExporter commented 9 years ago
I think too that creating the ManyToMany as OneToMany&ManyToOne it would bring 
us the basic infrastructure to handle the ManyToMany relationships.

Original comment by bernyrod...@gmail.com on 19 Jun 2010 at 6:47

GoogleCodeExporter commented 9 years ago

Original comment by bniemyjski on 8 Jul 2010 at 11:29

GoogleCodeExporter commented 9 years ago
I have lots of ManyToMany relationships to deal with and I can't wait to get 
started.  Are there any code samples showing where/how to modify the templates?

Or is the best way to simply override it by customizing the code?

Are there any good examples or best practices of any kind?

TIA

Original comment by bill.n...@gmail.com on 27 Aug 2010 at 7:58

GoogleCodeExporter commented 9 years ago
Hello,

We currently don't support many-to-many but it is on my short list of things 
that I really really really want to support. I've looked into this for 
countless hours on the best approach.... If you would be willing to tackle this 
issue with me that would be awesome, just let me know.

We have an association property located in the EntityCodeTemplate for many to 
many relationships. I would really like to implement the many to many without 
the immediate table. How are you implementing m2m now?

Thanks
-Blake Niemyjski

Original comment by bniemyjski on 30 Aug 2010 at 11:19

GoogleCodeExporter commented 9 years ago
I am just starting this now.  I presumed I was going to use the 'OnFetched' and 
add the many to many call to populate a manually added property after the 
object had been retrieved.  Preserve during regeneration was the goal.

I have to warn you, I'm not a great programmer by *any* stretch.  

Original comment by bill.n...@gmail.com on 30 Aug 2010 at 9:58

GoogleCodeExporter commented 9 years ago
Hello,

This might work. I'd have to take a look at it :). As long as it works for you 
is the only thing that matters in the end.

Thanks
-Blake Niemyjski

Original comment by bniemyjski on 31 Aug 2010 at 2:10

GoogleCodeExporter commented 9 years ago
Right.  I believe that probably the main drawback is going out to the datastore 
twice instead of loading it on the first try.  I am sure there will be 
performance implications for some applications.  In that case, you could 
replace the entire 'OnFetch' with the partial class (setting Cancel to true).

Not sure how this plays into lazy loading because I haven't thought it all the 
way through, yet.

Original comment by bill.n...@gmail.com on 31 Aug 2010 at 8:04

GoogleCodeExporter commented 9 years ago
Hello,

I'd really like to do this with one call :).

Thanks
-Blake Niemyjski

Original comment by bniemyjski on 31 Aug 2010 at 11:22

GoogleCodeExporter commented 9 years ago

Original comment by bniemyjski on 9 Mar 2012 at 1:14

GoogleCodeExporter commented 9 years ago
Here is a simple  change I implemented to support Many To Many relationship for 
CSLA C#. This works for me. It may not work in every situation.

Add the following to AssociationExtensions.cs.

 public static string BuildObjectInitializerManyToMany(this Association association, bool usePropertyName)
        {
            string parameters = string.Empty;
           //System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (AssociationMember associationMember in association)
            {
if (associationMember.AssociationType == AssociationType.ManyToMany)
                {
if (associationMember.AssociatedColumn.IsNullable && 
associationMember.AssociatedColumn.SystemType != "System.String" && 
associationMember.AssociatedColumn.SystemType != "System.Byte[]") continue;
                        parameters += string.Format(", {0} = {1}", associationMember.ToManyTableKeyName, associationMember.AssociatedMemberPropertyName ); 
                                   }
            }
            return parameters.TrimStart(new[] { ',', ' ' });
                   }

Add the following to Properties.cst

<%foreach(Association association in Entity.AssociatedManyToMany) {

    // For now, don't generate properties based on tables generated as generics.
    if(association.GenericProperty == string.Empty) {
        string associationIntermediateClass =  association.TableName;
        string associationIntermediateClassToPlural = CodeSmith.Engine.StringUtil.ToPlural( association.TableName);
        string associationIntermediateClassPrivateMember = CodeSmith.SchemaHelper.Util.NamingConventions.PrivateMemberVariableName(associationIntermediateClassToPlural);
        string associationIntermediateClassPropertyName = CodeSmith.SchemaHelper.Util.NamingConventions.PropertyName(associationIntermediateClassToPlural);

        %>
        //AssociatedManyToMany IntermediateClass
        private static readonly PropertyInfo< <%= associationIntermediateClass %>List > <%= associationIntermediateClassPrivateMember %>Property = RegisterProperty < <%= associationIntermediateClass %>List>(p => p.<%= associationIntermediateClassPropertyName %>, Csla.RelationshipTypes.Child);
        <% if(association.HasDescription) { %>
        /// <summary>
        /// <%= association.Description %>
        /// </summary>
        <% } %>
        public <%= associationIntermediateClass %>List <%= associationIntermediateClassPropertyName %>
        {
            get
            {
                bool cancel = false;
                OnChildLoading(<%= associationIntermediateClassPrivateMember %>Property, ref cancel);

                if (!cancel)
                {
        <% if(UseLazyLoading) { %>
                    if(!FieldManager.FieldExists(<%= associationIntermediateClassPrivateMember %>Property))
                    {
        <%// if(IncludeSilverlightSupport) { %>
            //#if SILVERLIGHT

            //#else
        <%// } %>

                    //cms changed BuildObjectInitializer BuildObjectInitializerManyToMany
                    var criteria = new <%= BusinessProjectName %>.<%= associationIntermediateClass %>Criteria {<%= association.BuildObjectInitializerManyToMany(true) %>};
                     <%//= association.BuildNullableObjectInitializer(true)%>

                     if(<%= association.BuildNullCheckStatement(true, true, false, false) %>!<%= BusinessProjectName %>.<%= associationIntermediateClass %>List.Exists(criteria))
                        LoadProperty(<%= associationIntermediateClassPrivateMember %>Property, <%= BusinessProjectName %>.<%= associationIntermediateClass %>List.NewList());
                      else
                        LoadProperty(<%= associationIntermediateClassPrivateMember %>Property, <%= BusinessProjectName %>.<%= associationIntermediateClass %>List.<%= association.SearchCriteria.MethodName%>(<%= association.SearchCriteria.Members.BuildPropertyVariableArguments() %>));
<% //} %>
<% //if(IncludeSilverlightSupport) { %>
//#endif
<% //} %>
                    }
        <% } //if(UseLazyLoading)  %>
                }

                return GetProperty(<%= associationIntermediateClassPrivateMember %>Property);
            }
        }

    <% } //if(association.GenericProperty == string.Empty %> 

<%} //foreach(Association association in Entity.AssociatedManyToMany) { %>

Original comment by bniemyjski on 9 Mar 2012 at 11:56

GoogleCodeExporter commented 9 years ago
Returning the intermediary table is important because that table may contain 
data about the relationship. Also from the intermediary table you can get the 
parent tables. So for me it was not that big of deal not to get the other side 
because I could go to the intermediate child and get the other side 
relationship. I was not designing a Many To Many relationship. I just add 
another foreign key relationship to a child table. This created a Many to Many 
relationship. The generator then did not create property for the child table. 
And that produce a build error because the parent object no longer had a 
property for the child.

 My database is to too complex know to give you as a test case. But it would seem fairly easy to reproduce.
If you build out a database like Car Manufacture, Tire Manufacture, Car Model, 
Tire Model, CarModel-TireModel. In CarModel-TireModel you might have a field 
like Position, that would tell where on the car the tire goes.

I have also fixed the infinite looping problem the scripts had with third tier 
child relationships. So if you implement the change you may run into the 
looping problem.

Original comment by bniemyjski on 9 Mar 2012 at 11:56

GoogleCodeExporter commented 9 years ago
Issue 582 has been merged into this issue.

Original comment by bniemyjski on 9 Mar 2012 at 11:56