I would keep the validation at the entity level. Here you can check that the required properties are set, their values are correct and you can also compare properties on the entity as well. This ensures that the entity, regardless of other entities, is in a valid state.
In the Service layer you can validate any entities passed into the method by calling a Validate method and you can also compare to entities within the database.
In the instance of validating whether a ID is unique you could add a method on your repository called GetById whereby you pass in the ID of the entity you want to check and if it returns NULL, then you didn't find an entity with that ID therefore its unique.
For example:
public class MyRepository
{
public MyEntity GetById(int id)
{
return _entitySet.FirstOrDefault( item => item.Id == id );
}
}
public class MyService
{
public void ServiceMethod(Entity entity)
{
if( _repository.GetById( entity.Id ) == null)
{
// entity.Id is unique!
}
else
{
// entity.Id is not unique!
}
}
}
Each of your repositories will have access to the entities is manages, such as an ObjectSet in Entity Framework (I think it's called that), so you can safely place any shared validation, in the context of a specific entity, on the repository.
For example:
public class MyRespository
{
public bool IsIdUnique(int id)
{
Entity entity = _entitySet.FirstOrDefault( item => item.Id == id );
return entity == null ? true : false;
}
}
public class MyService
{
public void ServiceMethod(Entity entity)
{
if( _repository.IsIdUnqiue(entity.Id) )
{
// entity.Id is unique!
}
else
{
// entity.Id is not unique!
}
}
}
You can also add the GetById to the MyService class above and have the IsIdUnique method call that rather than retype the lambda. This way you can reuse the GetById logic.