Entity Framework Contextual Validation - c#

How would you implement validation for entity framework entities when different validation logic should be applied in certain situations?
For example, validate the entity in one way if the user is an admin, otherwise validate in a different way.

I put validation attributes on context-specific, dedicated edit models.
The entity has only validations which apply to all entities.

Before I start talking about how to do this with VAB, let me say that you will have to really think your validation rules over. While differentiating validations between roles is possible, it does mean that the object that a user in one roles saves, is invalid for another user. This means that a user in a certain role might need to change that object before it can save it. This can also happen for the same user when it is promoted to another role. If you're sure about doing this, please read on.
This seems like a good job for Enterprise Library's Validation Application Block (VAB), since it allows validation of these complex scenarios. When you want to do this, forget attribute based validation; it simply won't work. You need configuration based validation for this to work.
What you can do using VAB is using a configuration file that holds the actual validation. It depends a bit on what the actual validation rules should be, but what you can do is create a base configuration that always holds for every object in your domain. And next create one or more configurations that contain only the extended validations. Say, for instance, that you've got a validation_base.config file, a validation_manager.config and a validation_admin.config file.
What you can do is merge those validations together depending on the role of the user. Look for instance at this example that creates three configuration sources, based on the configuration file:
var base = new FileConfigurationSource("validation_base.config");
var mngr = new FileConfigurationSource("validation_manager.config");
var admn = new FileConfigurationSource("validation_admin.config");
Now you have to merge these files into (at least) two configurations. One containing the base + manager and the other that contains the base + admin rules. While merging is not something that is supported out of the box, this article will show you how to do it. When using the code in that article, you will be able to do this:
var managerValidations =
new ValidationConfigurationSourceCombiner(base, mngr);
var adminValidations =
new ValidationConfigurationSourceCombiner(base, admn);
The last thing you need to do is to wrap these validations in a class that return the proper set based on the role of the user. You can that like this:
public class RoleConfigurationSource : IConfigurationSource
{
private IConfigurationSource base;
private IConfigurationSource managerValidations;
private IConfigurationSource adminValidations;
public RoleConfigurationSource()
{
this.base = new FileConfigurationSource("validation_base.config");
var mngr = new FileConfigurationSource("validation_manager.config");
var admn = new FileConfigurationSource("validation_admin.config");
managerValidations =
new ValidationConfigurationSourceCombiner(base, mngr);
adminValidations =
new ValidationConfigurationSourceCombiner(base, admn);
}
public ConfigurationSection GetSection(string sectionName)
{
if (sectionName == ValidationSettings.SectionName)
{
if (Roles.UserIsInRole("admin"))
{
return this.adminValidations;
}
else
{
return this.managerValidations;
}
}
return null;
}
#region IConfigurationSource Members
// Rest of the IConfigurationSource members left out.
// Just implement them by throwing an exception from
// their bodies; they are not used.
#endregion
}
Now this RoleConfigurationSource can be created once and you can supply it when you validate your objects, as follows:
static readonly IConfigurationSource validationConfiguration =
new RoleConfigurationSource();
Validator customerValidator =
ValidationFactory.CreateValidator<Customer>(validationConfiguration);
ValidationResults results = customerValidator.Validate(customer);
if (!results.IsValid)
{
throw new InvalidOperationException(results[0].Message);
}
Please note that the Validation Application Block is not an easy framework. It take some time to learn it. When your application is big enough, your specific requirements however, will justify its use. If you choose the VAB, start by reading the "Hands-On Labs" document. If you have problems, come back here at SO ;-)
Good luck.

Until I hear a brighter idea, I'm doing this:
public partial class MyObjectContext
{
ValidationContext ValidationContext { get; set; }
partial void OnContextCreated()
{
SavingChanges += new EventHandler(EntitySavingChanges);
}
private void EntitySavingChanges(object sender, EventArgs e)
{
ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted)
.Where(entry => entry.Entity is IValidatable).ToList().ForEach(entry =>
{
var entity = entry.Entity as IValidatable;
entity.Validate(entry, ValidationContext);
});
}
}
interface IValidatable
{
void Validate(ObjectStateEntry entry, ValidationContext context);
}
public enum ValidationContext
{
Admin,
SomeOtherContext
}
public partial class MyEntity : IValidatable
{
public ValidationContext ValidationContext { get; set; }
public void Validate(ObjectStateEntry entry, ValidationContext context)
{
// this validation doesn't apply to admins
if (context != ValidationContext.Admin)
{
// validation logic here
}
}
}

Related

ASP .NET Model Validation: Is it ok to access DBContext inside the Model?

Working with ASP .NET MVC I have a model called Entity1 and I need to do a custom validation inside of it.
I searched for a while and found out that implementing IValidatableObject I could implement the Validate method to do what I want. Now the question I have in this process is that I need to validate a property of Entity1 with another property of related Entity2 (by related I mean Data base relationship).
What I have is this:
public partial class Entity1: IValidatableObject
{
private EntitiesContext db = new EntitiesContext ();
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!Validation1())
{
yield return new ValidationResult(#"Error message.", new[] { "Property1" });
}
}
private bool Validation1()
{
if (this.Property1 != db.Entity2.First().Property2)
{
return false;
}
return true;
}
}
This is a simplified example of what I'm trying to do, but what I'm trying to figure out is if the use of "db" object to make the validation is well done right there. Obviously I can polish it later with some Dependency Injection, but I want to be sure if this is the right way to make that kind of validation or if another way exists to achieve exactly that.
PS: I tried to access the relationship like this too, but the relationship is always null:
this.Property1 != this.Entity2.Property2
In the later, this.Entity2 is always null.
Thanks in advance! :)

How to unit test simple property has validator set?

I have similar rules for some properties in multiple model objects and I want to replace them with custom property validators to avoid code duplication in unit tests.
I have my property validator:
public class IntIdPropertyValidator: PropertyValidator
{
public IntIdPropertyValidator()
: base("Property {PropertyName} should be greater than 0")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
var value = (int)context.PropertyValue;
return value > 0;
}
}
And wiring it up in model validator class:
public class SomeRequestValidator : AbstractValidator<CreateWordRequest>
{
public SomeRequestValidator()
{
RuleFor(x => x.Id).SetValidator(new IntIdPropertyValidator());
}
}
Tried to test:
[Test]
public void Validate_IdHasValidator_Success()
{
Init();
validator.ShouldHaveChildValidator(x => x.Id, typeof(IntIdPropertyValidator));
}
But test always fails.
So, how can I test that validator is actually set for property Id?
You are using ShouldHaveChildValidator in the wrong way. Id is a simple type.
ShouldHaveChildValidator is being in used on complex types. (see also the source code)
The right way to test the property is to pass valid objects and invalid objects and then varify using ShouldNotHaveValidationErrorFor and ShouldHaveValidationErrorFor:
[Test]
public void Should_have_error_when_Id_Is_Ilegal() {
validator.ShouldHaveValidationErrorFor(p => p.Id, new CreateWordRequest());
}
[Test]
public void Should_not_have_error_when_Id_Is_Legal() {
validator.ShouldNotHaveValidationErrorFor(p => p.Id, new CreateWordRequest()
{
Id = 7
});
}
Edit
The following code will do the verification you were looking for:
[Test]
public void Validate_IdHasValidator_Success()
{
var validator = new SomeRequestValidator();
var descriptor = validator.CreateDescriptor();
var matchingValidators = descriptor.GetValidatorsForMember(
Extensions.GetMember<CreateWordRequest, int>(x => x.Id).Name);
Assert.That(matchingValidators.FirstOrDefault(), Is.InstanceOf<IntIdPropertyValidator>());
}
I'd like to explain you the reason that you shouldn't use the above code.
When you UT class you verify that the class behavior won't be harmed.
When you create a custom validator, you create a class with a responsibility to verify specific model( --> business rules)...
Id is a simple type with a business rules according to his parent model.
Therefore you need to verify the business rules of Id through the model validator.
Let's assume that one of your models suddenly need to change. In this case you don't have any validation that any of you existing business rules won't harmed(or you decide to make changes inside IntIdPropertyValidator, such a move will affect anywhere, even if you didn't want to).
Creating a custom Property Validator is very good for code maintenance however, the tests should be against the model validator.
On complex types the story is quite different:
Usually complex types has their own business rules. In this case, you have to create a custom validator for them, and then verify that the parent validator use the right validator. Another thing to verify is: If the complex type is Null or complex rules such as "when the property value is X and then complex type state is Y"...

Is it wrong to dynamically add "data-val" and "data-val-required" in the View?

I have a ViewModel that I can decorate with the [Required] attribute (see below). I've come to the point where I need to let the client control which fields are required or not. They can configure this trough XML and all this info is stored in the Model when it's first created. Now I have fields that are not decorated with [Required] but still need to get validated (as per "user settings") before submitting (for example the Phone field).
public class MyBusinessObjectViewModel
{
[Required]
public string Email { get; set; } //compulsory
public string Phone { get; set; } //not (yet) compulsory, but might become
}
If the user will not enter the Phone number, the data will still get posted. Wanting not to mess with custom validators, I just add the "data-val" and "data-val-required" attributes to the Html, like this:
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("data-val", "true");
dict.Add("data-val-required", "This field is required.");
#Html.TextBoxFor(x => x, dict);
This forces the client side validation for all the properties that are dynamically set as required. Is this good practice? What kind of side effects can I expect?
You should look into extending the meta model framework with your own metadata provider to do the actual binding between your site's configuration and the model metadata. You can actually set the required property flag to true on the property model metadata during the metadata creation process. I can't remember for sure whether this causes the built in editor templates to generate the attribute, but I think it does. Worst case scenario you can actually create and attach a new RequiredAttribute to the property, which is a tad bit kluggy, but works pretty well in certain scenarios.
You could also do this with IMetadataAware attributes, especially if Required is the only metadata aspect your users can customize, but the implementation really depends on what you're trying to do.
One major advantage of using a custom ModelMetadataProvider in your specific case is that you can use dependency injection (via ModelMetadataProviders) to get your customer settings persistence mechanism into scope, whereas with the data attribute you only get to write an isolated method that runs immediately after the metadata model is created.
Here is a sample implementation of a custom model metadata provider, you'd just have to change the client settings to whatever you wanted to use.
UPDATED but not tested at all
public class ClientSettingsProvider
{
public ClientSettingsProvider(/* db info */) { /* init */ }
public bool IsPropertyRequired(string propertyIdentifier)
{
// check the property identifier here and return status
}
}
public ClientRequiredAttribute : Attribute
{
string _identifier;
public string Identifier { get { return _identifer; } }
public ClientRequiredAttribute(string identifier)
{ _identifier = identifier; }
}
public class RequiredModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
ClientSettings _clientSettings;
public RequiredModelMetadataProvider(ClientSettings clientSettings)
{
_clientSettings = clientSettings;
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
// alternatively here is where you could 'inject' a RequiredAttribute into the attributes list
var clientRequiredAttribute = attributes.OfType<ClientRequiredAttribute>().SingleOrDefault();
if(clientRequiredAttribute != null && _clientSettings.IsPropertyRequired(clientRequiredAttribute.Identifier))
{
// By injecting the Required attribute here it will seem to
// the base provider we are extending as if the property was
// marked with [Required]. Your data validation attributes should
// be added, provide you are using the default editor templates in
// you view.
attributes = attributes.Union(new [] { new RequiredAttribute() });
}
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
// REMOVED, this is another way but I'm not 100% sure it will add your attributes
// Use whatever attributes you need here as parameters...
//if (_clientSettings.IsPropertyRequired(containerType, propertyName))
//{
// metadata.IsRequired = true;
//}
return metadata;
}
}
USAGE
public class MyModel
{
[ClientRequired("CompanyName")]
public string Company { get; set; }
}
public class MyOtherModel
{
[ClientRequired("CompanyName")]
public string Name { get; set; }
public string Address { get; set; }
}
Both of these models would validate the string "CompanyName" against your client settings provider.
Not wanting to mess with custom validators, so you messed in the View obfuscating the logic of your validation by removing it from the place where it is expected to be found.
Really, don't be afraid of creating a custom attribute validator. What you are doing right now is getting a technical debt.

Where to put global rules validation in DDD

I'm new to DDD, and I'm trying to apply it in real life. There is no questions about such validation logic, as null check, empty strings check, etc - that goes directly to entity constructor/property. But where to put validation of some global rules like 'Unique user name'?
So, we have entity User
public class User : IAggregateRoot
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
// other data and behavior
}
And repository for users
public interface IUserRepository : IRepository<User>
{
User FindByName(string name);
}
Options are:
Inject repository to entity
Inject repository to factory
Create operation on domain service
???
And each option more detailed:
1 .Inject repository to entity
I can query repository in entities constructor/property. But I think that keeping reference to repository in entity is a bad smell.
public User(IUserRepository repository)
{
_repository = repository;
}
public string Name
{
get { return _name; }
set
{
if (_repository.FindByName(value) != null)
throw new UserAlreadyExistsException();
_name = value;
}
}
Update: We can use DI to hide dependency between User and IUserRepository via Specification object.
2. Inject repository to factory
I can put this verification logic in UserFactory. But what if we want to change name of already existing user?
3. Create operation on domain service
I can create domain service for creating and editing users. But someone can directly edit name of user without calling that service...
public class AdministrationService
{
private IUserRepository _userRepository;
public AdministrationService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void RenameUser(string oldName, string newName)
{
if (_userRepository.FindByName(newName) != null)
throw new UserAlreadyExistException();
User user = _userRepository.FindByName(oldName);
user.Name = newName;
_userRepository.Save(user);
}
}
4. ???
Where do you put global validation logic for entities?
Thanks!
Most of the times it is best to place these kind of rules in Specification objects.
You can place these Specifications in your domain packages, so anybody using your domain package has access to them. Using a specification, you can bundle your business rules with your entities, without creating difficult-to-read entities with undesired dependencies on services and repositories. If needed, you can inject dependencies on services or repositories into a specification.
Depending on the context, you can build different validators using the specification objects.
Main concern of entities should be keeping track of business state - that's enough of a responsibility and they shouldn't be concerned with validation.
Example
public class User
{
public string Id { get; set; }
public string Name { get; set; }
}
Two specifications:
public class IdNotEmptySpecification : ISpecification<User>
{
public bool IsSatisfiedBy(User subject)
{
return !string.IsNullOrEmpty(subject.Id);
}
}
public class NameNotTakenSpecification : ISpecification<User>
{
// omitted code to set service; better use DI
private Service.IUserNameService UserNameService { get; set; }
public bool IsSatisfiedBy(User subject)
{
return UserNameService.NameIsAvailable(subject.Name);
}
}
And a validator:
public class UserPersistenceValidator : IValidator<User>
{
private readonly IList<ISpecification<User>> Rules =
new List<ISpecification<User>>
{
new IdNotEmptySpecification(),
new NameNotEmptySpecification(),
new NameNotTakenSpecification()
// and more ... better use DI to fill this list
};
public bool IsValid(User entity)
{
return BrokenRules(entity).Count() == 0;
}
public IEnumerable<string> BrokenRules(User entity)
{
return Rules.Where(rule => !rule.IsSatisfiedBy(entity))
.Select(rule => GetMessageForBrokenRule(rule));
}
// ...
}
For completeness, the interfaces:
public interface IValidator<T>
{
bool IsValid(T entity);
IEnumerable<string> BrokenRules(T entity);
}
public interface ISpecification<T>
{
bool IsSatisfiedBy(T subject);
}
Notes
I think Vijay Patel's earlier answer is in the right direction, but I feel it's a bit off. He suggests that the user entity depends on the specification, where I belief that this should be the other way around. This way, you can let the specification depend on services, repositories and context in general, without making your entity depend on them through a specification dependency.
References
A related question with a good answer with example: Validation in a Domain Driven Design.
Eric Evans describes the use of the specification pattern for validation, selection and object construction in chapter 9, pp 145.
This article on the specification pattern with an application in .Net might be of interest to you.
I would not recommend disallowing to change properties in entity, if it's a user input.
For example, if validation did not pass, you can still use the instance to display it in user interface with validation results, allowing user to correct the error.
Jimmy Nilsson in his "Applying Domain-Driven Design and Patterns" recommends to validate for a particular operation, not just for persisting. While an entity could be successfully persisted, the real validation occurs when an entity is about to change it's state, for example 'Ordered' state changes to 'Purchased'.
While creating, the instance must be valid-for-saving, which involves checking for uniqueness. It's different from valid-for-ordering, where not only uniqueness must be checked, but also, for example, creditability of a client, and availability at the store.
So, validation logic should not be invoked on a property assignments, it should be invoked upon aggregate level operations, whether they are persistent or not.
Edit: Judging from the other answers, the correct name for such a 'domain service' is specification. I've updated my answer to reflect this, including a more detailed code sample.
I'd go with option 3; create a domain service specification which encapsulates the actual logic that performs the validation. For example, the specification initially calls a repository, but you could replace it with a web service call at a later stage. Having all that logic behind an abstract specification will keep the overall design more flexible.
To prevent someone from editing the name without validating it, make the specification a required aspect of editing the name. You can achieve this by changing the API of your entity to something like this:
public class User
{
public string Name { get; private set; }
public void SetName(string name, ISpecification<User, string> specification)
{
// Insert basic null validation here.
if (!specification.IsSatisfiedBy(this, name))
{
// Throw some validation exception.
}
this.Name = name;
}
}
public interface ISpecification<TType, TValue>
{
bool IsSatisfiedBy(TType obj, TValue value);
}
public class UniqueUserNameSpecification : ISpecification<User, string>
{
private IUserRepository repository;
public UniqueUserNameSpecification(IUserRepository repository)
{
this.repository = repository;
}
public bool IsSatisfiedBy(User obj, string value)
{
if (value == obj.Name)
{
return true;
}
// Use this.repository for further validation of the name.
}
}
Your calling code would look something like this:
var userRepository = IoC.Resolve<IUserRepository>();
var specification = new UniqueUserNameSpecification(userRepository);
user.SetName("John", specification);
And of course, you can mock ISpecification in your unit tests for easier testing.
I’m not an expert on DDD but I have asked myself the same questions and this is what I came up with:
Validation logic should normally go into the constructor/factory and setters. This way you guarantee that you always have valid domain objects. But if the validation involves database queries that impact your performance, an efficient implementation requires a different design.
(1) Injecting Entities: Injecting entities can be technical difficult and also makes managing application performance very hard due to the fragmentation of you database logic. Seemingly simple operations can now have an unexpectedly performance impact. It also makes it impossible to optimize your domain object for operations on groups of the same kind of entities, you no longer can write a single group query, and instead you always have individual queries for each entity.
(2) Injecting repository: You should not put any business logic in repositories. Keep repositories simple and focused. They should act as if they were collections and only contain logic for adding, removing and finding objects (some even spinoff the find methods to other objects).
(3) Domain service This seems the most logical place to handle the validation that requires database querying. A good implementation would make the constructor/factory and setters involved package private, so that the entities can only be created / modified with the domain service.
I would use a Specification to encapsulate the rule. You can then call when the UserName property is updated (or from anywhere else that might need it):
public class UniqueUserNameSpecification : ISpecification
{
public bool IsSatisifiedBy(User user)
{
// Check if the username is unique here
}
}
public class User
{
string _Name;
UniqueUserNameSpecification _UniqueUserNameSpecification; // You decide how this is injected
public string Name
{
get { return _Name; }
set
{
if (_UniqueUserNameSpecification.IsSatisifiedBy(this))
{
_Name = value;
}
else
{
// Execute your custom warning here
}
}
}
}
It won't matter if another developer tries to modify User.Name directly, because the rule will always execute.
Find out more here
In my CQRS Framework, every Command Handler class also contains a ValidateCommand method, which then calls the appropriate business/validation logic in the Domain (mostly implemented as Entity methods or Entity static methods).
So the caller would do like so:
if (cmdService.ValidateCommand(myCommand) == ValidationResult.OK)
{
// Now we can assume there will be no business reason to reject
// the command
cmdService.ExecuteCommand(myCommand); // Async
}
Every specialized Command Handler contains the wrapper logic, for instance:
public ValidationResult ValidateCommand(MakeCustomerGold command)
{
var result = new ValidationResult();
if (Customer.CanMakeGold(command.CustomerId))
{
// "OK" logic here
} else {
// "Not OK" logic here
}
}
The ExecuteCommand method of the command handler will then call the ValidateCommand() again, so even if the client didn't bother, nothing will happen in the Domain that is not supposed to.
in short you have 4 options:
IsValid method: transition an entity to a state (potentially invalid) and ask it to validate itself.
Validation in application services.
TryExecute pattern.
Execute / CanExecute pattern.
read more here
Create a method, for example, called IsUserNameValid() and make that accessible from everywhere. I would put it in the user service myself. Doing this will not limit you when future changes arise. It keeps the validation code in one place (implementation), and other code that depends on it will not have to change if the validation changes You may find that you need to call this from multiple places later on, such as the ui for visual indication without having to resort to exception handling. The service layer for correct operations, and the repository (cache, db, etc.) layer to ensure that stored items are valid.
I like option 3. Simplest implementation could look so:
public interface IUser
{
string Name { get; }
bool IsNew { get; }
}
public class User : IUser
{
public string Name { get; private set; }
public bool IsNew { get; private set; }
}
public class UserService : IUserService
{
public void ValidateUser(IUser user)
{
var repository = RepositoryFactory.GetUserRepository(); // use IoC if needed
if (user.IsNew && repository.UserExists(user.Name))
throw new ValidationException("Username already exists");
}
}
Create domain service
Or I can create domain service for
creating and editing users. But
someone can directly edit name of user
without calling that service...
If you properly designed your entities this should not be an issue.

Is there a better way to handle validation in LINQ to SQL?

Are there any ways, besides throwing exceptions, that one can go about using the partial validation methods in LINQ to SQL to cancel the insert of a record?
I can understand that you don't want to throw an exception directly after a property is set with an invalid value. This approach makes it difficult to communicate correctly to the user what actually is wrong. However, I think it's better to keep away from using those partial validation methods. IMO you want to throw an exception when your model is invalid, but only just before you're persisting your model to the database.
I advise you to use a validation framework and integrate it with your LINQ to SQL DataContext class. Here's an example of how to do this with The Enterprise Library Validation Application Block, but the concept will work for every validation framework you pick:
public partial class NorthwindDataContext
{
public override void SubmitChanges(ConflictMode failureMode)
{
ValidationResult[] = this.Validate();
if (invalidResults.Length > 0)
{
// You should define this exception type
throw new ValidationException(invalidResults);
}
base.SubmitChanges(failureMode);
}
private ValidationResult[] Validate()
{
// here we use the Validation Application Block.
return invalidResults = (
from entity in this.GetChangedEntities()
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
from result in results
select result).ToArray();
}
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}
[Serializable]
public class ValidationException : Exception
{
public ValidationException(IEnumerable<ValidationResult> results)
: base("There are validation errors.")
{
this.Results = new ReadOnlyCollection<ValidationResult>(
results.ToArray());
}
public ReadOnlyCollection<ValidationResult> Results
{
get; private set;
}
}
There are several validation frameworks available, such as DataAnnotations and
the Enterprise Library Validation Application Block (VAB). VAB is very suited for doing this. With LINQ to SQL your entities are generated, so you'll need to use the configuration based approach that VAB offers (don’t try decorating your entities with attributes). By overriding the SubmitChanges method you can make sure the validation gets triggered just before entities are persisted. My SO answers here and here contain useful information about using VAB.
I've written a few interesting articles about integrating VAB with LINQ to SQL here and here. The nice thing about LINQ to SQL (compared to Entity Framework 1.0) is that a lot of useful metadata is generated. When combining this with VAB you can use this metadata to validate your model, without having to hook up every validation manually. Especially validations as maximum string length and not null can be extracted from the model. Read here how to do this.
VAB to the rescue!
Ultimately this indicates that at you last line of defence (before any database constraints, at least) your data was invalid. If you want to do something other than scream loudly, then perhaps verify the data (via any of a multitude of approaches) before adding it to the insert list.
As an additional thought, you could try overriding SubmitChanges (on the data-context); obtain the change-set, verify the inserts and remove (delete-on-submit, which IIRC checks the insert list and drops them) any that you've decided were mistakes. Then call the base.SubmitChanges. But to me this is a bit backwards.
To illustrate, this only does a single insert (not two as requested), but I don't like this approach. At all. As long as we're clear ;-p
namespace ConsoleApplication1 {
partial class DataClasses1DataContext { // extends the generated data-context
public override void SubmitChanges(
System.Data.Linq.ConflictMode failureMode) {
var delta = GetChangeSet();
foreach (var item in delta.Inserts.OfType<IEntityCheck>()) {
if (!item.IsValid()) {
GetTable(item.GetType()).DeleteOnSubmit(item);
}
}
base.SubmitChanges(failureMode);
}
}
public interface IEntityCheck { // our custom basic validation interface
bool IsValid();
}
partial class SomeTable : IEntityCheck { // extends the generated entity
public bool IsValid() { return this.Val.StartsWith("d"); }
}
static class Program {
static void Main() {
using (var ctx = new DataClasses1DataContext()) {
ctx.Log = Console.Out; // report what it does
ctx.SomeTables.InsertOnSubmit(new SomeTable { Val = "abc" });
ctx.SomeTables.InsertOnSubmit(new SomeTable { Val = "def" });
ctx.SubmitChanges();
}
}
}
}

Categories