Для выборки я бы посоветовал мапить на table-values functions, т.к. они при выборки оптимизируются (к примеру, если после вызова в .NET примените where), в отличие от процедур, которые вытаскивают всю выборку. Опять же, такой вариант позволит вам работать с ними как с IQueryable, что является несомненным плюсом.
Если у вас EDMX, то эти функции замапятся автоматически мастером. Если Code First, то вам нужен
https://github.com/moozzyk/CodeFirstFunctions, Nuget пакет называется EntityFramework.CodeFirstStoreFunctions.
Мы использовали (и используем данный подход) с 2013 года - за это время проблем с ним не было. Еще момент, это работает только для MSSQL, если что-то другое используете, то этот вариант не подойдет.
К примеру, в моей случае, БД внезапно стала PostgreSQL, и я сделал немного по-другому. Выборку замапил на представление, где сделал умножение JOIN-ов, чтобы получить всевозможные варианты (в моем случае это связка сущность-ресурсы-язык_ресурса:
CREATE OR REPLACE VIEW public.v_companies AS
SELECT c.id,
c.isdeleted,
c.hversion,
c.modifydate,
c.modifierid,
l.id AS languageid,
CASE
WHEN cr.id IS NOT NULL THEN cr.name
ELSE cr_fb.name
END AS name
FROM companies c
JOIN languages l ON true --- тада!
LEFT JOIN company_resources cr ON c.id = cr.companyid AND cr.languageid = l.id
LEFT JOIN company_resources cr_fb ON c.id = cr_fb.companyid AND cr_fb.languageid = (( SELECT crx.languageid
FROM company_resources crx
WHERE c.id = crx.companyid
LIMIT 1))
ORDER BY c.id, (
CASE
WHEN cr.name IS NOT NULL THEN 0
ELSE 1
END)
И сделал extension-метод для получения модели данного View, куда я отдавал CurrentLanguageId и делал по нему фильтрацию.