Question

Is the essence of Project, the creation of which is necessary to check whether there is already an entity with the same name. When editing needs such as checking, but keep in mind that the old and the new name of the entity can be matched. You also need to display an error message. For this I use interface IValidatableObject, but do not know how to tell the Validate method the object is currently being edited or created

Était-ce utile?

La solution 3

Problem is solved using method ModelState.AddModelError (string, string) in actions Edit and Create.

[HttpPost]
[HandleError(View="AjaxError")]
public ActionResult Edit(ProjectsViewData data)
{
    if (ModelState.IsValid)
    {
        if (!ContainsProject(data.CurrentObject.Name))
        {
            db.Projects.Attach(data.CurrentObject);
            db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
            db.SaveChanges();
            return Projects(data);
        }
        else
        {
            int projectId = (from p in db.Projects
                                where p.Name == data.CurrentObject.Name
                                select p.ProjectID).FirstOrDefault();
            if (projectId == data.CurrentObject.ProjectID)
            {
                db.Projects.Attach(data.CurrentObject);
                db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
                db.SaveChanges();
                return Projects(data);
            }
            else
            {
                ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
            }
        }
    }

    data.ObjectToEdit = data.CurrentObject;
    return Projects(data);
}

[HttpPost]
[HandleError(View = "AjaxError")]
public ActionResult Create(ProjectsViewData data)
{
    if (ModelState.IsValid)
    {
        if (!ContainsProject(data.CurrentObject.Name))
        {
            db.Projects.AddObject(data.CurrentObject);
            db.SaveChanges();
            return Projects(data);
        }
        else
        {
            ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
        }
    }

    data.ObjectToAdd = data.CurrentObject;
    return Projects(data);
}

Helper method:

private bool ContainsProject(string projectName)
{
    if (projectName != null)
    {
        projectName = Regex.Replace(projectName.Trim(), "\\s+", " ");
        List<string> projects = new List<string>();
        var projectNames = (from p in db.Projects
                            select p.Name.Trim()).ToList();
        foreach (string p in projectNames)
        {
            projects.Add(Regex.Replace(p, "\\s+", " "));
        }
        if (projects.Contains(projectName))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

Autres conseils

DbContext.ValidateEntity takes the IDictionary<Object, Object> items as the second parameter. You can pass any data there and the data you pass will be passed to IValidatableObject.Validate in the ValidationContext.Items

Assuming you refer to check EF cant do for you.
This is actually difficult to check. You are checking an entity after it has been added to the context. It should not check itself and needs to consider other items in context that are not yet saved. As well as the DB. There are several 3 combinations plus an self recognition. Record a an entity record in LOCAL when ID is blank/new ie multiple new inserts needs careful coding. (Consider using temp IDs)

the not yet saved entries should be in context

Context.Set<TPoco>().Local

and get data from DB and keep in a temp list. BUT dont put in context. Or use a SECOND context.

 var matchingSet = Context.Set<TPoco>().AsNoTracking()   // not into context...
                      .Where(t=>t.field == somevalue).ToList(); 

So what about logical and actual duplicates on the DB. Logical duplicates are duplicates on a field with no unique index that from a business perspective should be unique.

If you want to check those...

You need to read the DB.... BUT if these records are currently being changed, you CAN NOT just put them into the Context. You would overwrite them. But what if the values the logical key values have changed? Something caused a logical dup on a record on the DB may no longer be a dup once saved or vice verse. Is that still a dup or not ?

So you need to decide how you match LOCAL versus loaded records. Ie check LOCAL and matching DB records and decidr what to do if a record is in both, only local or only db. LOCAL ONLY and DB Only is easy.
But in both... That is your business process decision.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top