My technique is to pass in all the ids to the stored procedure. You can do this with XML.
Using the XML data type, you can DELETE the ids in dbPhones that are NOT IN the ids for userPhones, UPDATE the matching records and INSERT the new ones in one procedure call.
Here is a SQL Server 2005 XML Example. Hope this helps. You can cut and paste it into a query window and it will work (for SQL 2005+)
--Assume this is your data table. In real life it would be a SQL server table
DECLARE @DBData TABLE ( DataName varchar(50), DataDesc varchar(50))
INSERT INTO @DBData
VALUES ('One', 'Number One')
INSERT INTO @DBData
VALUES ('Two', 'Number Two')
INSERT INTO @DBData
VALUES ('Three', 'Number Three')
INSERT INTO @DBData
VALUES ('Four', 'Numero Quatro')
SELECT * FROM @DBData
-- This is the data you would pass in.
-- We would expect that One will update, Two, Three and Four
-- will be deleted (since they are not in the data) and
-- Five will be added.
DECLARE @XMLData xml
SELECT @XMLData = '
<root>
<item>
<DataName>One</DataName>
<DataDesc>Number 1 Renamed</DataDesc>
</item>
<item>
<DataName>Five</DataName>
<DataDesc>Adding Five</DataDesc>
</item>
</root>'
--Update DataDesc where the items match
UPDATE DBTable
SET DataDesc = CONVERT(varchar(50), XTable.Item.query('./DataDesc/text()'))
FROM @XMLData.nodes('/root/item') AS XTable(Item)
INNER JOIN
@DBData DBTable ON CONVERT(varchar(50), XTable.Item.query('./DataName/text()')) = DBTable.DataName
SELECT * FROM @DBData
--Insert items that are not in the table yet.
INSERT INTO @DBData(DataName, DataDesc)
SELECT CONVERT(varchar(50), XTable.Item.query('./DataName/text()')),
CONVERT(varchar(50), XTable.Item.query('./DataDesc/text()'))
FROM @XMLData.nodes('/root/item') AS XTable(Item)
WHERE CONVERT(varchar(50), XTable.Item.query('./DataName/text()')) NOT IN (SELECT DataName FROM @DBData)
SELECT * FROM @DBData
--Remove items that are not in the XML document/table
DELETE FROM @DBData
WHERE DataName NOT IN (
SELECT CONVERT(varchar(50), XTable.Item.query('./DataName/text()'))
FROM @XMLData.nodes('/root/item') AS XTable(Item))
SELECT * FROM @DBData
Further reading:
at MSDN[
^]