views:

86

answers:

3

Hi Guys,

I have alluded to this issue in my other question, but i think it's worthwhile breaking it out into its own question, as it's not really dependant on the other scenarios i mentioned.

Anyways - onto the Q, don't know if this is possible. Looking for a solution/workaround.

I have a Class Library, with nothing but POCO's:

MyCompany.MyProject.Domain.POCO

This assembly has a POCO like this:

public class Post
{
   public int PostId { get; set; }
   public int Name { get; set; }
      ...
}

Now, i have another Class Library, which is my DAL/Repository, and uses Entity Framework 4.0 for the persistence:

MyCompany.MyProject.Repositories

This assembly has a reference to the POCO project, as it needs to be perform CRUD operations on the POCO's (grab DB objects, project into POCO's, return, as well as modify POCO's).

Now, i also have a Web Application, which has a reference to both the POCO and Repository assembly.

If i do this:

somePOCO.PostId = 10;

I get a SQLException, as PostId is an IDENTITY field in the database, and hence should not be explicity set.

Is there a way i can hide the setter for these special properties, so that only the repository has access to the setter?

I can't think of a way to do it with regular accessibility modifiers (as none of them suit the scenario), can you guys think of a workaround?

+2  A: 

Mark all your setters as internal, then add the InternalsVisibleTo Attribute to your POCOs assembly:

 [assembly: InternalsVisibleTo( "MyCompany.MyProject.Repositories" )]  
Nescio
You're on the right track, but wouldn't this say "all internals" are only visible to the repository? I only want to restrict the "setter", not both the "get/set" for ALL properties. Know what i mean?
RPM1984
My bad - your right (@Luke Schafer's) answer helped with that.
RPM1984
Although i gave the answer to Luke, +1 for being correct too.
RPM1984
+4  A: 

you could make the setter internal, and make the internals visible to the repository assembly

[assembly: InternalsVisibleTo("MyLibrary.Repositories")]
public class Post
{
   public int PostId { get; internal set; }
   public int Name { get; internal set; }
      ...
}

This means that everything can 'get' those properties, but only this assembly, and the assembly containing the repository, can 'set'

Luke Schafer
Yep, that's what i was looking for. @Nescio alluded to that, but you made it clearer with the internal set on the POCO. Thanks.
RPM1984
no problems. I also put in an additional clarifying comment
Luke Schafer
+2  A: 

Luke Schafer's is a good answer. It satisfies the technical requirement of the question. But I'd advise caution simply because this may not address the problem in the future.

Not to suggest over engineering but perhaps you might want to think about abstracting away further what you are doing with these objects that have the settable ID property. It may suffice to create this 'visibility' with this attribute decoration but i think it's sort of a hack for the problem. It might be cleaner to encapsulate the interaction between these objects with something else, thus removing the setter access from consuming code.

cottsak
I agree it's a `hack` - but i can't think of any other solution (that doesnt compromise my architecture). Can you?
RPM1984
I don't know how this works in EF but i have a very similar setup but i use L2S. I don't worry about `ID` properties being set somewhere by accident because in INSERT cases (which i assume you refer from the IDENTITY SQLException) the `ID` property is ignored. Is that not the same with you?
cottsak
Well, a factory within the POCO could handle creation, and therefore alteration, of the model. The factory would be exposed publicly. This would allow the repository to create a model and set its properties, but not allow alteration by other assemblies after the fact. It depends whether or not you require alteration.
Luke Schafer
Unfortunately, it's not. L2SQL doesnt use pure POCO's, they are generated by L2SQL with all the metadata/sql attributes/access in the designer.cs file. I'm using hand-coded pure POCO's.
RPM1984
@Luke Schafer - if i went directly down that path, how could i make changes to the POCO's? In my UI, i need to be able say change the post title. I can do this by saying post.Title = "Foo", then invoking "SaveChanges" on my repository. If i "dont allow alteration", how can i modify POCO's? I'd have to expose all the properties as method parameters. (ie public void ModifyPost(string title)).
RPM1984
Ok i guess i missed some info. I use POCOs too, i custom map them to the L2S entities in my 'data layer'. Perhaps it's that abstraction that removes the problem your having from my life. The original idea came from [Rob Conery](http://blog.wekeroad.com/2008/04/07/mvc-storefront-part-1). Some people might say that such additional abstraction is not necessary and a waste of time but like you, i can't have that 'data stuff' in my model. So you prob understand.
cottsak
I agree RPM1984 that you want to pass your POCO Model objects right up to the UI. You need to allow ModelBinders and the like to create/update the Model Objects for you (before they're sent back down to the business/service/data layers).
cottsak
Also, EF is of course much more intelligent/mature than L2SQL :) This is the error i get when i try to update the PostID: `System.InvalidOperationException: The property 'PostId' is part of the object's key information and cannot be modified. ` As part of SaveChanges, EF validates all the changes in the ObjectStateManager. This is where it has a cry.
RPM1984
Fair enuf. I'd be frustrated too if i were you i guess. I'd not like to have the ORM/Data Layer force me into something like this.
cottsak